如何衡量一个接口的性能好坏,一般我们至少会关注以下三个指标
- 接口的 RT 你怎么知道?
- 是否有异常响应?
- 主要慢在哪里?
在初期,公司刚起步的时候,可能多会采用如下单体架构,对于单体架构我们该用什么方式来计算以上三个指标呢?
![图片[1]-分布式追踪系统的原理及作用-编程社](https://cos.bianchengshe.com/wp-content/uploads/2023/01/image-161.png?imageMogr2/format/webp/interlace/1/quality/100)
最容易想到的显然是用 AOP
![图片[2]-分布式追踪系统的原理及作用-编程社](https://cos.bianchengshe.com/wp-content/uploads/2023/01/image-160.png?imageMogr2/format/webp/interlace/1/quality/100)
使用 AOP 在调用具体的业务逻辑前后分别打印一下时间即可计算出整体的调用时间,使用 AOP 来 catch 住异常也可知道是哪里的调用导致的异常。
微服务架构
在单体架构中由于所有的服务,组件都在一台机器上,所以相对来说这些监控指标比较容易实现,不过随着业务的快速发展,单体架构必然会朝微服务架构发展,如下
![图片[3]-分布式追踪系统的原理及作用-编程社](https://cos.bianchengshe.com/wp-content/uploads/2023/01/image-159.png?imageMogr2/format/webp/interlace/1/quality/100)
如图示:一个稍微复杂的微服务架构
如果有用户反馈某个页面很慢,我们知道这个页面的请求调用链是 A —–> C —–> B —–> D,此时如何定位可能是哪个模块引起的问题。每个服务 Service A,B,C,D 都有好几台机器。怎么知道某个请求调用了服务的具体哪台机器呢?
![图片[4]-分布式追踪系统的原理及作用-编程社](https://cos.bianchengshe.com/wp-content/uploads/2023/01/image-158.png?imageMogr2/format/webp/interlace/1/quality/100)
可以明显看到,由于无法准确定位每个请求经过的确切路径,在微服务这种架构下有以下几个痛点
- 排查问题难度大,周期长
- 特定场景难复现
- 系统性能瓶颈分析较难
分布式调用链就是为了解决以上几个问题而生,它主要的作用如下
- 自动采取数据
- 分析数据产生完整调用链:有了请求的完整调用链,问题有很大概率可复现
- 数据可视化:每个组件的性能可视化,能帮助我们很好地定位系统的瓶颈,及时找出问题所在
通过分布式追踪系统能很好地定位如下请求的每条具体请求链路,从而轻易地实现请求链路追踪,每个模块的性能瓶颈定位与分析。
![图片[5]-分布式追踪系统的原理及作用-编程社](https://cos.bianchengshe.com/wp-content/uploads/2023/01/image-157.png?imageMogr2/format/webp/interlace/1/quality/100)
分布式调用链标准 – OpenTracing
知道了分布式调用链的作用,那我们来看下如何实现分布式调用链的实现及原理, 首先为了解决不同的分布式追踪系统 API 不兼容的问题,诞生了 OpenTracing 规范,OpenTracing 是一个轻量级的标准化层,它位于应用程序/类库和追踪或日志分析程序之间。
![图片[6]-分布式追踪系统的原理及作用-编程社](https://cos.bianchengshe.com/wp-content/uploads/2023/01/image-156.png?imageMogr2/format/webp/interlace/1/quality/100)
这样 OpenTracing 通过提供平台无关,厂商无关的 API,使得开发人员能够方便地添加追踪系统的实现。
说到这大家是否想过 Java 中类似的实现?还记得 JDBC 吧,通过提供一套标准的接口让各个厂商去实现,程序员即可面对接口编程,不用关心具体的实现。这里的接口其实就是标准,所以制定一套标准非常重要,可以实现组件的可插拔。
![图片[7]-分布式追踪系统的原理及作用-编程社](https://cos.bianchengshe.com/wp-content/uploads/2023/01/image-155.png?imageMogr2/format/webp/interlace/1/quality/100)
接下来我们来看 OpenTracing 的数据模型,主要有以下三个
- Trace:一个完整请求链路
- Span:一次调用过程(需要有开始时间和结束时间)
- SpanContext:Trace 的全局上下文信息, 如里面有traceId
理解这三个概念非常重要,为了让大家更好地理解这三个概念,我特意画了一张图
![图片[8]-分布式追踪系统的原理及作用-编程社](https://cos.bianchengshe.com/wp-content/uploads/2023/01/image-154.png?imageMogr2/format/webp/interlace/1/quality/100)
如图示,一次下单的完整请求完整就是一个 Trace, 显然对于这个请求来说,必须要有一个全局标识来标识这一个请求,每一次调用就称为一个 Span,每一次调用都要带上全局的 TraceId, 这样才可把全局 TraceId 与每个调用关联起来,这个 TraceId 就是通过 SpanContext 传输的,既然要传输显然都要遵循协议来调用。如图示,我们把传输协议比作车,把 SpanContext 比作货,把 Span 比作路应该会更好理解一些。
理解了这三个概念,接下来我看看分布式追踪系统如何采集统一图中的微服务调用链
![图片[9]-分布式追踪系统的原理及作用-编程社](https://cos.bianchengshe.com/wp-content/uploads/2023/01/image-153.png?imageMogr2/format/webp/interlace/1/quality/100)
我们可以看到底层有一个 Collector 一直在默默无闻地收集数据,那么每一次调用 Collector 会收集哪些信息呢。
- 全局 trace_id:这是显然的,这样才能把每一个子调用与最初的请求关联起来
- span_id: 图中的 0,1,1.1,2,这样就能标识是哪一个调用
- parent_span_id:比如 b 调用 d 的 span_id 是 1.1,那么它的 parent_span_id 即为 a 调用 b 的 span_id 即 1,这样才能把两个紧邻的调用关联起来。
有了这些信息,Collector 收集的每次调用的信息如下
![图片[10]-分布式追踪系统的原理及作用-编程社](https://cos.bianchengshe.com/wp-content/uploads/2023/01/image-152.png?imageMogr2/format/webp/interlace/1/quality/100)
根据这些图表信息显然可以据此来画出调用链的可视化视图如下
![图片[11]-分布式追踪系统的原理及作用-编程社](https://cos.bianchengshe.com/wp-content/uploads/2023/01/image-151.png?imageMogr2/format/webp/interlace/1/quality/100)
于是一个完整的分布式追踪系统就实现了。
以上实现看起来确实简单,但有以下几个问题需要我们仔细思考一下
- 怎么自动采集 span 数据:自动采集,对业务代码无侵入
- 如何跨进程传递 context
- traceId 如何保证全局唯一
- 请求量这么多采集会不会影响性能
接下我来看看 SkyWalking 是如何解决以上四个问题的
暂无评论内容