什么是链路追踪?分布式系统如何实现链路追踪?

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

在分布式系统尤其是微服务系统中一次外部请求往往需要内部多个模块多个中间件多台机器的相互调用才能完成。在这一系列的调用中可能有些是串行的而有些是并行的。在这种情况下我们如何才能确定这整个请求调用了哪些应用哪些模块哪些节点以及它们的先后顺序和各部分的性能如何呢

这就是涉及到链路追踪。

什么是链路追踪?

链路追踪是分布式系统下的一个概念它的目的就是要解决上面所提出的问题也就是将一次分布式请求还原成调用链路将一次分布式请求的调用情况集中展示比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等。
图片

链路追踪的原理

衡量一个接口我们一般会看三个指标

1、接口的 RTRoute-Target你怎么知道?
2、接口是否有异常响应?
3、接口请求慢在哪里?

1、单体架构时代

在创业初期我们的系统一般是单体架构如下

图片

对于单体架构我们可以使用 AOP切面编程来统计这三个指标如下

图片

使用 AOP切面编程对原本的逻辑代码侵入更少我们只需要在调用具体的业务逻辑前后分别打印一下时间即可计算出整体的调用时间。另外使用 AOP切面编程来捕获异常也可知道是哪里的调用导致的异常。

2、微服务架构

随着业务的快速发展单体架构越来越不能满足需要我们的系统慢慢会朝微服务架构发展如下

图片

在微服务架构下当有用户反馈某个页面很慢时虽然我们知道这个请求可能的调用链是 A -----> C -----> B -----> D但服务这么多而且每个服务都有好几台机器怎么知道问题具体出在哪个服务哪台机器呢

图片

这也是微服务这种架构下的几个痛点

1、排查问题难度大周期长
2、特定场景难复现
3、系统性能瓶颈分析较难

分布式调用链就是为了解决以上几个问题而生它主要的作用如下

1、自动采取数据
2、分析数据产生完整调用链有了请求的完整调用链问题有很大概率可复现
3、数据可视化每个组件的性能可视化能帮助我们很好地定位系统的瓶颈及时找出问题所在

通过分布式追踪系统我们能很好地定位请求的每条具体请求链路从而轻易地实现请求链路追踪进而定位和分析每个模块的性能瓶颈。

图片

3、分布式调用链标准OpenTracing

OpenTracing 是一个轻量级的标准化层它位于应用程序/类库和追踪或日志分析程序之间。它的出现是为了解决不同的分布式追踪系统 API 不兼容的问题。

图片

OpenTracing 通过提供与平台和厂商无关的 API使得开发人员能够方便地添加追踪系统就像单体架构下的AOP切面编程一样。

说到这里大家是否想过 Java 中类似的实现还记得 JDBC 吧JDBC 就是通过提供一套标准的接口让各个厂商去实现程序员即可面对接口编程不用关心具体的实现。这里的接口其实就是标准。所以制定一套标准非常重要可以实现组件的可插拔。

图片

OpenTracing 的数据模型主要有以下三个

  • **Trace**一个完整请求链路

  • **Span**一次调用过程需要有开始时间和结束时间

  • **SpanContext**Trace 的全局上下文信息如里面有traceId

为了让大家更好地理解这三个概念我特意画了一张图

图片

如图所示一次下单的完整请求就是一个 Trace。TraceId是这个请求的全局标识。内部的每一次调用就称为一个 Span每个 Span 都要带上全局的 TraceId这样才可把全局 TraceId 与每个调用关联起来。这个 TraceId 是通过 SpanContext 传输的既然要传输显然都要遵循协议来调用。如图所示如果我们把传输协议比作车把 SpanContext 比作货把 Span 比作路应该会更好理解一些。

理解了这三个概念接下来我们就看看分布式追踪系统是如何采集图中的微服务调用链。

图片

我们可以看到底层有一个 Collector 一直在默默无闻地收集数据那么每一次调用 Collector 会收集哪些信息呢。

1、全局 trace_id这是显然的这样才能把每一个子调用与最初的请求关联起来
2、span_id: 图中的 011.12这样就能标识是哪一个调用
3、parent_span_id比如 b 调用 d 的 span_id 是 1.1那么它的 parent_span_id 即为 a 调用 b 的 span_id 即 1这样才能把两个紧邻的调用关联起来。

有了这些信息Collector 收集的每次调用的信息如下

图片

根据这些图表信息显然可以据此来画出调用链的可视化视图如下

图片

于是一个完整的分布式追踪系统就实现了。

以上实现看起来确实简单但有以下几个问题需要我们仔细思考一下

1、怎么自动采集 span 数据自动采集对业务代码无侵入
2、如何跨进程传递 context
3、traceId 如何保证全局唯一
4、请求量这么多采集会不会影响性能

接下来我们来看看链路追踪系统 SkyWalking 是如何解决以上四个问题的。

链路追踪系统SkyWalking的原理

1、怎么自动采集 span 数据

SkyWalking 采用了插件化 + javaagent 的形式来实现了 span 数据的自动采集这样可以做到对代码的无侵入性。插件化意味着可插拔扩展性好。如下图所示

图片

2、如何跨进程传递 context

我们知道数据一般分为 header 和 body就像 http 有 header 和 bodyRocketMQ 也有 MessageHeaderMessage Body。body 一般放着业务数据所以不宜在 body 中传递 context应该在 header 中传递 context如图所示

图片

dubbo 中的 attachment 就相当于 header所以我们把 context 放在 attachment 中这样就解决了 context 的传递问题。

图片

图片

3、traceId 如何保证全局唯一

要保证全局唯一 我们可以采用分布式或者本地生成的 ID。使用分布式的话需要有一个发号器每次请求都要先请求一下发号器会有一次网络调用的开销。所以 SkyWalking 最终采用了本地生成 ID 的方式它采用了大名鼎鼎的 snowflow 算法性能很高。

图片

不过 snowflake 算法有一个众所周知的问题时间回拨这个问题可能会导致生成的 id 重复。那么 SkyWalking 是如何解决时间回拨问题的呢。

图片

每生成一个 id都会记录一下生成 id 的时间lastTimestamp如果发现当前时间比上一次生成 id 的时间lastTimestamp还小那说明发生了时间回拨此时会生成一个随机数来作为 traceId。这里可能就有同学要较真了可能会觉得生成的这个随机数也会和已生成的全局 id 重复是否再加一层校验会好点。

这里要说一下系统设计上的方案取舍问题了首先如果针对产生的这个随机数作唯一性校验无疑会多一层调用会有一定的性能损耗但其实时间回拨发生的概率很小发生之后由于机器时间紊乱业务会受到很大影响所以机器时间的调整必然要慎之又慎再加上生成的随机数重合的概率也很小综合考虑这里确实没有必要再加一层全局唯一性校验。对于技术方案的选型一定要避免过度设计过犹不及。

4、请求量这么多全部采集会不会影响性能?

如果对每个请求调用都采集那毫无疑问数据量会非常大但反过来想一下是否真的有必要对每个请求都采集呢其实没有必要我们可以设置采样频率只采样部分数据SkyWalking 默认设置了 3 秒采样 3 次其余请求不采样如图所示

图片

这样的采样频率其实足够我们分析组件的性能了按 3 秒采样 3 次这样的频率来采样数据会有啥问题呢。理想情况下每个服务调用都在同一个时间点这样的话每次都在同一时间点采样确实没问题。如下图所示

图片

但在生产上每次服务调用基本不可能都在同一时间点调用因为期间有网络调用延时等实际调用情况很可能是下图这样

图片

这样的话就会导致某些调用在服务 A 上被采样了在服务 BC 上不被采样也就没法分析调用链的性能。

那么 SkyWalking 是如何解决的呢

它是这样解决的如果上游有携带 Context 过来说明上游采样了则下游将强制采集数据这样可以保证链路完整。

SkyWalking 的基础架构

SkyWalking 的基础如下架构可以说几乎所有的的分布式调用都是由以下几个组件组成的。

图片

首先当然是节点数据的定时采样采样后将数据定时上报将其存储到 ES, MySQL 等持久化层有了数据自然而然可根据数据做可视化分析。

[图片上传失败…(image-a9fec9-1673754852336)]

SkyWalking 的性能如何

[图片上传失败…(image-45d20d-1673754852336)]

如下是官方的测评数据

图片

图中蓝色代表未使用 SkyWalking 的表现橙色代表使用了 SkyWalking 的表现以上是在 TPS 为 5000 的情况下测出的数据可以看出不论是 CPU内存还是响应时间使用 SkyWalking 带来的性能损耗几乎可以忽略不计。

接下来我们再来看 SkyWalking 与另一款业界比较知名的分布式追踪工具 Zipkin、Pinpoint 的对比在采样率为 1 秒 1 个线程数 500请求总数为 5000 的情况下做的对比。

可以看到在关键的响应时间上 Zipkin117msPinPoint201ms远逊于 SkyWalking22ms从性能损耗这个指标上看SkyWalking 完胜

图片

再看下另一个指标对代码的侵入性如何。

ZipKin 是需要在应用程序中埋点的对代码的侵入强而 SkyWalking 采用 javaagent + 插件化这种修改字节码的方式可以做到对代码无任何侵入。除了性能和对代码的侵入性上 SkyWaking 表现不错外它还有以下优势几个优势

  • **对多语言的支持组件丰富**目前其支持 Java、 .Net Core、PHP、NodeJS、Golang、LUA 语言组件上也支持dubbo, mysql 等常见组件大部分能满足我们的需求。

  • **扩展性**对于不满足的插件我们按照 SkyWalking 的规则手动写一个即可新实现的插件对代码无入侵。

以上虽然主要以SkyWalking为例来介绍链路追踪系统但是并不是说其他链路追踪系统一点不适用。具体选择什么样的大家可按实际场景灵活选择。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6