美文网首页原云生实践
分布式链路追踪实践(一) - 分布式链路追踪方案对比

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

作者: codeandcode | 来源:发表于2020-12-08 21:04 被阅读0次

    分布式链路追踪(全链路追踪)是分布式系统或者微服务架构中服务监控、性能优化的有效手段。分布式链路追踪有 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 。

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

    相关文章

      网友评论

        本文标题:分布式链路追踪实践(一) - 分布式链路追踪方案对比

        本文链接:https://www.haomeiwen.com/subject/gdiqgktx.html