分布式链路追踪实践(一) - 分布式链路追踪方案对比

分布式链路追踪(全链路追踪)是分布式系统或者微服务架构中服务监控、性能优化的有效手段。分布式链路追踪有 Jaeger, Zipkin, SkyWalking 等方案,我们详细讲解它们的架构原理;

  • 分布式链路追踪方案选型
  • 分布式链路追踪实践
  • 分布式链路追踪 SDK

⾯向 DevOps 的诊断与分析系统

  • Logging - 集中式⽇志系统: ⽤于记录离散的事件。例如,应⽤程序的调试信息或错误信息。它是我们诊断问题的依据。
  • Tracing - 分布式追踪系统: ⽤于记录请求范围内的信息。例如,⼀次远程⽅法调⽤的执⾏过程和耗时。它是我们排查系统性能问题的利器。
  • Metrics - 集中式度量系统: ⽤于记录可聚合据。的数例如,队列的当前深度可被定义为⼀个度量值,在元素⼊队或出队时被更新;HTTP 请求个数可被定义为⼀个计数器,新请求到来时进⾏累加。

所以 Logging,Metrics 和 Tracing 有各⾃专注的部分。

ltm.png

全链路 - 分布式追踪

方案对比:

project.png
  • Drapper:google的Drapper--未开源,最早的APM

  • CAT:⼤众点评跨服务的跟踪功能与点评内部的RPC框架集成,这部分未开源且项⽬在2014.1已经停⽌维护。服务粒度的监控,通过代码埋点的⽅式来实现监控,⽐如: 拦截器,注解,过滤器等,对代码的侵⼊性较⼤,集成成本较⾼。

  • Hydra:京东Hydra与dubbo框架集成,对于服务级别的跟踪统计,现有业务可以⽆缝接⼊。对于细粒度的兴趣点,需要业务⼈员⼿动添加.开源项⽬已于2013年6⽉停⽌维护

  • PinPoint-naver:字节码探针技术,代码⽆侵⼊,体系完善不易修改,⽀持java,技术栈⽀持dubbo.其他语⾔社区⽀援中

  • Zipkin:java⽅便集成于springcloud,社区⽀持的插件也包括dubbo,rabbit,mysql,httpclient等(https://github.com/openzipkin/brave/tree/master/instrumentation),同时⽀持php,go,js等语⾔客户端,界⾯功能较为简单,本身⽆告警功能,可能需要⼆次开发。代码⼊侵度⼩。

  • Jaeger:Uber-Jaeger⽀持java/c++/go/node/php,在界⾯上较为完善(对⽐zipkin),但是也⽆告警功能。代码⼊侵度⼩。dubbo⽬前⽆插件⽀持,可⼆次开发。

  • Skywalking:华为开源,类似于PinPoint,⽬前还在apache孵化中,⽹上吞吐量对⽐中强于pinpoint (实际未验证), 本身⽀持dubbo

Jaeger

架构设计

Jaeger是Uber开发的⼀套分布式追踪系统,受启发于 dapper 和OpenZipkin,兼容 OpenTracing 标准,CNCF的开源项⽬。

Jaeger 架构设计:

jaeger.png
  • 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 这样的负载均衡器后⾯。

Agent 初始化类图

TUDPTransport:基于Thrift框架的UDP传输类。
TBufferedServer:基于TUDPTransport的UDP服务器类。
Processor:消息处理类,提供Serve和Stop两个接⼝。
ThriftProcessor:消息传递类,⽤于异步的将从UDPServer
这边接收到的span消息,送⾄AgentProcessor处理。
AgentProcessor:根据协议区分jaeger和zipkin消息,接收
并处理method为emitBatch的消息,发送⾄Reporter。
HTTPServerConfiguration:⽤于配置HTTPServer。
HTTPServer⽤于接收Collector的HTTP配置消息,配置采样
率等信息

jaeger_agent.png

Agent初始化序列图

  • CreateReporter:app/builder.go 中提供createMainReporter接⼝,在接⼝中调⽤Builder.CreateReporter接⼝。CreateReporter接⼝在 app/report/tchannel/builder.go中实现。CreateReporter接⼝中创建了⼀个tchannel类型的Reporter。

  • NewAgentProcessor:根据zipkin和jaeger两种协议类型,agent会创建各⾃的AgentProcessor。Jaeger类型的AgentProcessor实现在 thrift-gen/agent/agent.go。得到传回的对象后作为handler传⼊ ThriftProcessor。

  • getUDPServer:创建基于 thrift 的 UDP 服务器,并作为⼊参传⼊ ThriftProcessor。

  • GetHTTPServer:创建基于HTTP的服务器,⽤于处理 Collector下发的配置,设置采样率等信息。

jaeger_agent_ sequence.png

Agent数据流序列图

  • Serve:Agent为不同协议的ThriftProcessor创建多个协程,并调⽤其Serve接⼝。

  • processBuffer:在ThriftProcessor的Serve接⼝中根据配置创建多个协程⽤于并发处理span消息。

  • DataRecd:TBufferedServer在Buffer池的机制,避免了空间反复的 new 和 delete。此处将⽤完的数据包返回TBufferedServer,以便下次接收数据时再次使⽤。

  • Process:ThriftProcessor将接收到的数据转换成对应的协议格式后,传递到AgentProcessor中。

  • Process:AgentProcessor 解析消息 Method 头,如果为 EmitBatch 则调⽤对应回调进⾏处理。当前只⽀持EmitBatch消息。

综上所述,可以看出来Agent模块主要通过tchannel接收本机的UDP消息(实为span消息),再传递⾄thrift框架的Reporter,发送⾄Collector。在Agent消息处理过程中,都为⼆进制协议消息,⾮明⽂。Agent不对消息内容做任何修改。

jaeger_agent_data_sequence.png

SkyWalking

SkyWalking 架构设计

SkyWalking 的核⼼是数据分析和度量结果的存储平台,通过 HTTP 或 gRPC ⽅式向SkyWalking Collecter 提交分析和度量数据,SkyWalking Collecter 对数据进⾏分析和聚合,存储到 Elasticsearch、H2、MySQL、TiDB 等其⼀即可,最后我们可以通过 SkyWalking UI 的可视化界⾯对最终的结果进⾏查看。SkyWalking ⽀持从多个来源和多种格式收集数据:多种语⾔的 Skywalking Agent 、Zipkin v1/v2 、Istio 勘测、Envoy 度量等数据格式。

skywalking.png
  • SkyWalking 是针对分布式系统的 APM 系统,也被称为分布式追踪系统全⾃动探针监控,不需要修改应⽤程序代码。(查看⽀持的中间件和组件库列表:https://github.com/apache/incubator/skywalking )
  • ⽀持⼿动探针监控, 提供了⽀持 OpenTracing 标准的SDK。覆盖范围扩⼤到 OpenTracing-Java ⽀持的组件。 (查看OpenTracing组件⽀持表:https://github.com/opentracing-contrib/meta )
  • ⾃动监控和⼿动监控可以同时使⽤,使⽤⼿动监控弥补⾃动监控不⽀持的组件,甚⾄私有化组件。纯 Java 后端分析程序,提供 RESTful 服务,可为其他语⾔探针提供分析能⼒。⾼性能纯流式分析。
skywalking_arch2.png

SkyWalking 逻辑上分为四部分: 探针, 平台后端, 存储和⽤户界⾯。

  • 探针:基于不同的来源可能是不⼀样的, 但作⽤都是收集数据, 将数据格式化为 SkyWalking 适⽤的格式

  • 平台后端:是⼀个⽀持集群模式运⾏的后台, ⽤于数据聚合, 数据分析以及驱动数据流从探针到⽤户界⾯的流程. 平台后端还提供了各种可插拔的能⼒, 如不同来源数据(如来⾃ Zipkin)格式化, 不同存储系统以及集群管理. 你甚⾄还可以使⽤观测分析语⾔来进⾏⾃定义聚合分析

  • 存储:是开放式的. 你可以选择⼀个既有的存储系统, 如 ElasticSearch, H2 或 MySQL 集群
    (Sharding-Sphere 管理), 也可以选择⾃⼰实现⼀个存储系统. 当然, 我们⾮常欢迎你贡献新的存储系统实现

  • ⽤户界⾯:对于 SkyWalking 的最终⽤户来说⾮常炫酷且强⼤. 同样它也是可定制以匹配你已存在的后端的

探针限制

进程内传播在⼤多数情况下成为可能。许多⾼级编程语⾔(如 Java, .NET)都是⽤于构建业务系统. ⼤部分业务逻辑代码对于每⼀个请求来说都运⾏在同⼀个线程内, 这使得传播是基于线程 ID 的, 以确保上下⽂是安全的.仅仅对某些框架和库奏效。因为是代理来在运⾏时修改代码的, 这也意味着代理插件开发者事先就要知道 所要修改的代码是怎么样的. 因此, 在这种探针下通常会有⼀个已⽀持的列表清单.⽀持服务列表: https://github.com/apache/skywalking/blob/master/docs/en/setup/service-agent/java-agent/Supported-list.md

跨线程可能并⾮总是奏效 如上所述, 每个请求的代码⼤都运⾏在⼀个线程之内, 对于业务代码来说尤其如此. 但是在其他⼀些场景下, 它们也会在不同线程下⼯作, ⽐如指派任务到其他线程, 任务池, 以及批处理. 对于⼀些语⾔, 可能还提供了协程或类似的概念如 Goroutine, 使得开发者可以低开销地来执⾏异步操作, 在这些场景下, ⾃动打点可能会遇到⼀些问题。

动态探针技术

字节码增加技术(有的叫动态探针技术)来实现⽆侵⼊式的调⽤链采集。其核⼼实现原来还是基于JVM的javaagent机制来实现:
"-javaagent:$AGENT_PATH/-bootstrap-$VERSION.jar "
来指定skywalking agent加载路径,在启动的时候agent将在加载应⽤class⽂件之前做拦截并修改字节码,在class⽅法调⽤的前后加上链路采集逻辑,从⽽实现链路采集功能。
javaAgent的底层机制主要依赖JVMTI ,JVMTI全称JVM Tool Interface,是JVM暴露出来的⼀些供⽤户扩展的接⼝集合。JVMTI是基于事件驱动的,JVM每执⾏到⼀定的逻辑就会调⽤⼀些事件的回调接⼝(如果有的话),这些接⼝可以供开发者扩展⾃⼰的逻辑。但JVMTI都是⼀些接⼝合集,需要有接⼝的实现,这就⽤到了java的instrument,可以理解instrument是JVMTI的⼀种实现,为JVM提供外挂⽀持。

javaagent具体实现

使⽤:java -javaagent:myagent.jar=mode=test Test
javaagent 的主要功能如下:
• 可以在加载 class ⽂件之前做拦截,对字节码做修改
• 可以在运⾏期对已加载类的字节码做变更,但是这种情况下会有很多的限制,后⾯会详细说
• 还有其他⼀些⼩众的功能

◦获取所有已经加载过的类
◦获取所有已经初始化过的类(执⾏过 clinit ⽅法,是上⾯的⼀个⼦集)
◦获取某个对象的⼤⼩
◦将某个 jar 加⼊到 bootstrap classpath ⾥作为⾼优先级被 bootstrapClassloader 加载
◦将某个 jar 加⼊到 classpath ⾥供 AppClassloard 去加载
◦设置某些 native ⽅法的前缀,主要在查找 native ⽅法的时候做规则匹配

JVMTI 全称 JVM Tool Interface,是 JVM 暴露出来的⼀些供⽤户扩展的接⼝集合。JVMTI 是基于事件驱动的,JVM 每执⾏到⼀定的逻辑就会调
⽤⼀些事件的回调接⼝(如果有的话),这些接⼝可以供开发者扩展⾃⼰的逻辑。⽐如最常⻅的,我们想在某个类的字节码⽂件读取之后、类
定义之前修改相关的字节码,从⽽使创建的 class 对象是我们修改之后的字节码内容,那就可以实现⼀个回调函数赋给 jvmtiEnv(JVMTI 的运
⾏时,通常⼀个 JVMTIAgent 对应⼀个 jvmtiEnv,但是也可以对应多个)的回调⽅法集合⾥的 ClassFileLoadHook,这样在接下来的类⽂件加
载过程中都会调⽤到这个函数中。

instrument agent

instrument agent 实现了Agent_OnLoad和Agent_OnAttach两⽅法,也就是说在使⽤时,agent既可以在启动时加载,也可以在运⾏时动态加
载。其中启动时加载还可以通过类似-javaagent:myagent.jar的⽅式来间接加载 instrument agent,运⾏时动态加载依赖的是 JVM 的 attach 机制
( JVM Attach 机制实现),通过发送 load 命令来加载 agent。

skywalking_agent_structure.png

在启动时加载 instrument agent
启动时加载 instrument agent,具体过程都在InvocationAdapter.cAgent_OnLoad⽅法⾥,这⾥简单描述下过程:
创建并初始化 JPLISAgent
监听 VMInit 事件,在 vm 初始化完成之后做下⾯的事情:
创建 InstrumentationImpl 对象
监听 ClassFileLoadHook 事件
调⽤ InstrumentationImpl 的loadClassAndCallPremain⽅法,在这个⽅法⾥会调⽤ javaage
在运⾏时加载 instrument agent
上⾯会通过 JVM 的 attach 机制来请求⽬标 JVM 加载对应的 agent,过程⼤致如下:
创建并初始化 JPLISAgent
解析 javaagent ⾥ MANIFEST.MF ⾥的参数
创建 InstrumentationImpl 对象
监听 ClassFileLoadHook 事件
调⽤ InstrumentationImpl 的loadClassAndCallAgentmain⽅法,在这个⽅法⾥会调⽤ javaagent ⾥ MANIFEST.MF ⾥指定的Agent-Class类的
agentmain⽅法

skywalking_ui.png

Zipkin

Zipkin 组件设计

Zipkin是⼀个分布式追踪系统。它有助于收集解决微服务架构中延迟
问题所需的时序数据。它管理这些数据的收集和查找。Zipkin的设计
基于 Google Dapper论⽂。
共有四个组件构成了 Zipkin:

  • collector
  • storage
  • search
  • web UI
    Reporter是装配应⽤中⽤于向 Zipkin 发送数据的组件。Reporter 通过
    Transport 发送追踪数据到 Zipkin 的 Collector,Collector 持久化数据
    到 Storage 中。之后,API 从 Storage 中查询数据提供给 UI。
zipkin_arch.png

Zipkin 架构设计

  • Transport:
    装配库发送的跨度必须由装配的服务传输到 Collector。 有三种主要的传输类型:
    HTTP、Scribe 和 Kafka。更多信息查看跨度接收器。

  • Collector:
    ⼀旦追踪数据抵达 Zipkin Collector 守护进程,Zipkin Collector 为了查询,会对其进
    ⾏校验、存储和索引。

  • Storage:
    Zipkin 最初是构建在将数据存储在 Cassandra 中,因为 Cassandra 易跨站,⽀持
    灵活的 schema,并且在 Twitter 内部被⼤规模使⽤。然⽽,我们将这个组件做成了
    可插拔式的。在 Cassandra 之外,我们原⽣⽀持 ElasticSearch 和 MySQL。可作为
    第三⽅扩展提供给其它后端。

Zipkin 查询服务:

⼀旦数据被存储索引,我们就需要⼀种⽅式提取它。查询守护进程提供了⼀个简单
的 JSON API 查询和获取追踪数据。API 的主要消费者就是 Web UI。

Web UI:

我们创建了⼀个⽤户图形界⾯为追踪数据提供了⼀个漂亮的视图。Web UI 提供了基
于服务、时间和标记(annotation)查看追中数据的⽅法。注意:UI 没有内置的身
份认证功能。

zipkin_arch2.png
zipkin_community_support.png
zipkin_ui.png

总结

  1. 非侵入性,并且对 JAVA, .NET 等语言支持,可以选择 SkyWalking, 接入成本较小 ;
  2. 如果采用 OpenTracing 集成接入,可以选择 Jaeger 或者 Zipkin ,侵入性比较大,接入成本中等;
  3. Service Mesh Tracing 接入 (如 istio tracing ),侵入性较小,接入成本较小 ;

在生产中使用,需要看团队研发力量和需求,1-3 种方案均可以实施。
下一章和大家分享 自研 分布式链路追踪 SDK 。

原文: 分布式链路追踪实践(一)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容