目前不少的大中小公司都在探索和实践着微服务这种软件开发架构,将复杂庞大的重量型项目经过明肯定义的 API 拆分红多个小型可复用的独立服务单元或者说是服务组件,这样让应用程序更易于扩展和更快地开发,从而加速创新并缩短新功能的上市时间。可是复用和拆分依旧简化不了系统的复杂度,虽然微服务架构拆分了业务单元,可是各类组件之间的调用也是错中复杂,所以带来一系列的问题:node
对于服务的维护者来讲,观察某一个请求(事件)的整个生命周期也是很困难;nginx
难以进行用户体验优化web
后台真实错误缘由分析后端
分布式系统内各组件的调用状况等为了解决这个问题,曾在90年代末出现的Tracing技术流行了起来,在早期,出现了一大批优秀的 Tracing 软件:
api
Dapper(Google) : 各 tracer 的基础缓存
Zipkin微信
鹰眼(taobao)网络
谛听(盘古,阿里云云产品使用的Trace系统)架构
...并发
尽管分布式追踪系统发展很快,种类繁多,但核心步骤通常有三个:代码埋点
, 数据存储
、 查询展现
。但在数据采集过程当中,因为须要侵入用户代码,而且不一样系统的 API 并不兼容,这就致使了若是您但愿切换追踪系统,每每会带来较大改动,出现了痛点,就会有人解决,为了解决不一样的分布式追踪系统 API 不兼容的问题,诞生了 OpenTracing 规范,Opentracing也正是为了解决这样的痛点。
OpenTracing 进入 CNCF,正在为全球的分布式追踪,提供统一的概念和数据标准。
OpenTracing 经过提供平台无关、厂商无关的 API,使得开发人员可以方便的添加(或更换)追踪系统的实现。
也就是说,听从Opentracing的规范,就至关于在应用程序/类库和追踪或日志分析程序之间定义了一个轻量级的标准化层,解耦了代码和Tracing API。
那么tracing到底是什么?
在广义上,一个trace表明了一个事务或者流程在(分布式)系统中的执行过程。在OpenTracing标准中,trace是多个span组成的一个有向无环图(DAG),每个span表明trace中被命名并计时的连续性的执行片断。
分布式追踪中的每一个组件都包含本身的一个或者多个span。例如,在一个常规的RPC调用过程当中,OpenTracing推荐在RPC的客户端和服务端,至少各有一个span,用于记录RPC调用的客户端和服务端信息
一个父级的span会显示的并行或者串行启动多个子span。在OpenTracing标准中,甚至容许一个子span有个多父span(例如:并行写入的缓存,可能经过一次刷新操做写入动做)。
在一个分布式系统中,追踪一个事务或者调用流通常如上图所示。虽然这种图对于看清各组件的组合关系是颇有用的,可是,它不能很好显示组件的调用时间,是串行调用仍是并行调用,若是展示更复杂的调用关系,会更加复杂,甚至没法画出这样的图。另外,这种图也没法显示调用间的时间间隔以及是否经过定时调用来启动调用。一种更有效的展示一个典型的trace过程,以下图所示:
这种展示方式增长显示了执行时间的上下文,相关服务间的层次关系,进程或者任务的串行或并行调用关系。这样的视图有助于发现系统调用的关键路径。经过关注关键路径的执行过程,项目团队可能专一于优化路径中的关键位置,最大幅度的提高系统性能。例如:能够经过追踪一个资源定位的调用状况,明确底层的调用状况,发现哪些操做有阻塞的状况。
tracing,monitoring和logging
但是提及tracing,脑子就会有一些疑问,tracing,monitoring和logging之间究竟有什么区别呢?先来看一张图
对于监控来讲,好比咱们经常使用的Prometheus是经过pull的方式有频率的定量的向目标收集指标,而后将数据进行聚合计算,造成报告,对有问题的异常数据进行报警,因此Monitoring的需求并无包含很是高的并发量和通信量。反过来讲:高并发、大数据量的需求并不适用于Monitoring这个点。
在了解Opentracing以后,你会发现Optracing规范是有标准固定的格式的,这也是和logging最大的不一样,tracing搜集一个事件过程当中全部指定搜集的项,好比某个接口的请求时间,当收到某个SQL后,这个SQL的实行时间等,会将这些时间汇总到一个报告中,造成一个tracing,由于Tracing是针对某一个事件(通常来讲就是一个API),而这个API可能会和不少组件进行沟通,后续的全部的组件沟通不管是内部仍是外部的IO,都算做这个API调用的Tracing的一部分。能够想见在一个业务繁忙的系统中,API调用的数量已是天文数字,而其衍生出来的Tracing记录更是不得了的量。其特色就是高频、巨量,一个API会衍生出大量的子调用。
通常来讲咱们在大型系统中提到Logging说的都不是简单的日志,而是日志聚合系统。从本质上来讲,Monitoring和Tracing都是Logging,Logging是这三者中覆盖面最大的超集,而前二者则是其一部分的子集。Logging最麻烦的是,开发者也不会彻底知道最后记录进入到日志系统里的一共会有哪些东西,只有在使用(检索)的时候才可能须要汇总查询总量中的一部分。
每一个组件都有它本身存在的必要性:
Monitoring系统(Prometheus)从根本的需求和基本设计上就不可能支持Tracing和Logging:低频 vs 高频、低量 vs 高量,其从设计到实现就只为了监控服务
Tracing系统(Jaeger)对提供的数据有格式要求,且处理方式和通常的Logging也不一样,有更限定的应用范围
Logging系统(ELK)能够处理前二者的需求,但前二者的领域有更专业的工具就不推荐直接使用普通的日志聚合系统了;Logging系统通常用来处理大型系统的日志聚合以及检索查询
OpenTracing 实现之Jaeger 和 Zipkin
Jaeger目前是CNCF中的一个孵化项目,是 Uber 推出的一款开源分布式追踪系统,兼容 OpenTracing API,因此咱们这里主要说一说Opentracing的后起之秀jaeger。先来看看Jaeger的架构图:
Jaeger Client - 为不一样语言实现了符合 OpenTracing 标准的 SDK。应用程序经过 API 写入数据,client library 把 trace 信息按照应用程序指定的采样策略传递给 jaeger-agent。
Agent - 它是一个监听在 UDP 端口上接收 span 数据的网络守护进程,它会将数据批量发送给 collector。它被设计成一个基础组件,部署到全部的宿主机上。Agent 将 client library 和 collector 解耦,为 client library 屏蔽了路由和发现 collector 的细节。
Collector - 接收 jaeger-agent 发送来的数据,而后将数据写入后端存储。Collector 被设计成无状态的组件,所以您能够同时运行任意数量的 jaeger-collector。
Data Store - 后端存储被设计成一个可插拔的组件,支持将数据写入 cassandra、elastic search。
Query - 接收查询请求,而后从后端存储系统中检索 trace 并经过 UI 进行展现。Query 是无状态的,您能够启动多个实例,把它们部署在 nginx 这样的负载均衡器后面。
当处理的数据量很大的时候,jaeger-collector就会面临着一些性能的瓶颈,没法及时存储 jaeger-agent 发送来的数据,所以官方也支持使用kafka作为缓冲区,下面是架构图:
在熟悉了jaeger以后,为了更快的熟悉并掌握jaeger的使用,咱们在kubernetes上安装一下jaeger,而且在Edge Router Traefik2.0中使用jaeger配置一下tracing. jaeger的官方支持四种后端存储:
Cassandra 3.4+
Elasticsearch 5.x, 6.x, 7.x
Kafka
memory storage
由于咱们k8s集群里面已经运行着日志集群了,因此咱们直接时候用Elasticsearch做为jaeger的后端存储.
☸️ devcluster🔥 logging ~ 🐳 👉 k get podsNAME READY STATUS RESTARTS AGEes-cluster-0 1/1 Running 0 10des-cluster-1 1/1 Running 0 10des-cluster-2 1/1 Running 0 10dfluentd-es-7pk8j 1/1 Running 0 10dfluentd-es-glnpb 1/1 Running 0 10dfluentd-es-jpvlw 1/1 Running 0 10dfluentd-es-l4mqv 1/1 Running 0 10dfluentd-es-rff5d 1/1 Running 0 10dkibana-6c448bd4d8-ghl7l 1/1 Running 0 10d[ root@curl-69c656fd45-xqtqp:/ ]$ curl -XGET http://elasticsearch.logging.svc.cluster.local:9200/_cat/nodes10.244.2.147 57 99 26 6.15 6.24 6.04 mdi - es-cluster-010.244.2.148 77 99 26 6.15 6.24 6.04 mdi * es-cluster-110.244.2.149 66 99 26 6.15 6.24 6.04 mdi - es-cluster-2
首先咱们建立一个Namespace
kubectl create namespace tracing
接下来第一步是在同一个Namespace下配置一个ConfigMap,用于定义jaeger-agent,jaeger-query,jaeger-collector服务的配置。名称为
jaeger-configmap.yml
apiVersion: v1kind: ConfigMapmetadata: name: jaeger-configuration labels: app: jaeger app.kubernetes.io/name: jaeger namespace: tracingdata: span-storage-type: elasticsearch collector: | es: server-urls: http://elasticsearch.logging.svc.cluster.local:9200 #这里是咱们的es集群的访问地址 collector: zipkin: http-port: 9411 query: | es: server-urls: http://elasticsearch.logging.svc.cluster.local:9200 agent: | collector: host-port: "jaeger-collector:14267"
而后咱们经过list对象在tracing空间下定义jaeger-agent,jaeger-collector,jaeger-query以及它们的服务资源:
jaeger-production.yml
,配置文件内容比较多,能够在微信公众号内回复·jaeger·
获取最后,咱们在集群中安装一下便可:
kubectl apply -f jaeger-configmap.ymlkubectl apply -f jaeger-production.yml
查看服务是否正常运行了
☸️ devcluster🔥 tracing ~ 🐳 👉 kubectl get pods,svc,cmNAME READY STATUS RESTARTS AGEpod/jaeger-agent-4d5hz 1/1 Running 0 111mpod/jaeger-agent-574mg 1/1 Running 0 111mpod/jaeger-agent-5ztvr 1/1 Running 0 111mpod/jaeger-agent-sgn8s 1/1 Running 0 111mpod/jaeger-agent-xtlvv 1/1 Running 0 112mpod/jaeger-collector-77498bb8c-5xxf2 1/1 Running 0 130mpod/jaeger-query-b595fc78b-7qbxg 1/1 Running 0 130mNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEservice/jaeger-collector ClusterIP 10.110.33.231 <none> 14267/TCP,14268/TCP,9411/TCP 130mservice/jaeger-query ClusterIP 10.110.13.229 <none> 80/TCP 130mservice/zipkin ClusterIP 10.107.120.100 <none> 9411/TCP 130mNAME DATA AGEconfigmap/jaeger-configuration 4 146m
如何在外部访问k8s集群的jaeger-ui呢?咱们定义一个
jaeger-ingress.yml
apiVersion: traefik.containo.us/v1alpha1kind: IngressRoutemetadata: name: jaeger-query namespace: tracingspec: selector: app.kubernetes.io/name: jaeger app.kubernetes.io/component: query entryPoints: - web routes: - match: Host(`jaeger-query.xslimg.com`) kind: Rule services: - name: jaeger-query port: 80
咱们使用 kubectl apply-f jaeger-ingress.yml
就能够生成一个访问jaeger的路由了。
配置Traefik的静态配置文件,开启tracing,咱们修改一下k8s环境中的traefik的configmap,增长已下配置
... tracing: jaeger: samplingServerURL: http://192.168.10.231:5778/sampling samplingType: const samplingParam: 1.0 localAgentHostPort: 192.168.10.231:6831 # 这里是运行为daemonset的agent的主机地址 gen128Bit: true propagation: jaeger traceContextHeaderName: uber-trace-id collector: endpoint: http://jaeger-collector.tracing.svc.cluster.local:14268/api/traces?format=jaeger.thrift...
而后咱们重建一下traefik便可
kubectl apply -f traefik-configmap.ymlkubectl apply -f traefik-deployment.yaml
从新更新完配置文件和deployment.在重建成功后就能够访问:
这样咱们就能够在jaeger中查看traefik了
你也能够运行一个基于微服务框架的案例,经过案例进行深刻了解jaeger,分析并发访问服务后,观察jaeger收取到数据的具体表现。好了,opentracing入门和jaeger的实现就暂时说到这了。
目前100000+人已关注加入咱们

本文分享自微信公众号 - 云原生生态圈(CloudNativeEcoSystem)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。