分布式链路跟踪系统(一):Dapper 介绍

文章目录

  • 概述
  • 基本原理
  • Annotation
  • 植入
  • 采样率
  • 资料

概述

随着分布式系统和微服务的出现,一次用户请求可能会经过多个系统,不同服务之间的交互非常复杂,任何一个系统出错都可能影响整个请求的处理结果。以往的监控系统往往只能知道单个系统的健康状况、一次请求的成功失败,无法快速定位失败的根本原因。除此之外,复杂的分布式系统也面临这下面这些问题:

  1. 性能分析难:一个服务依赖很多服务,被依赖的服务也依赖了其他服务。如果某个接口耗时突然变长了,那未必是直接调用的下游服务慢了,也可能是下游的下游慢了造成的,如何快速定位耗时变长的根本原因呢?
  2. 链路梳理难:需求迭代很快,系统之间调用关系变化频繁,靠人工很难梳理清楚系统链路拓扑。
  3. 容量评估难:搞促销活动时,一般需要提前扩容以应对流量暴涨,然而不同促销活动、不同的流量入口对各个系统的影响是不同的,如何准确评估某个入口流量增长对下游系统的影响呢?

为了解决这些问题,Google 推出了一个分布式链路跟踪系统 Dapper,之后各个互联网公司都参照 Dapper 的思想推出了自己的分布式链路跟踪系统。

基本原理

下面的图里展示了一次用户请求引起了若干次系统之间的 RPC 调用,在这个示例里,用户请求首先到达前端系统 A,A 又调用了中间层系统 B、C,紧接着 C 又调用了两个后端系统 D、E。分布式链路跟踪系统就是要记录这一系列 RPC 调用的基本信息:调用关系、发生的时间、异常信息以及一些流量标记等。

分布式链路跟踪系统(一):Dapper 介绍_第1张图片

为了将一个请求触发的所有调用记录串联起来,需要有一个全局的 traceId,在整个调用链路上传递这个 traceId,并和每一天记录相关联。

分布式链路跟踪系统(一):Dapper 介绍_第2张图片

Dapper 的跟踪架构像是内嵌在 RPC 调用的树形结构,树节点是整个架构的基本单元,而每一个节点又是对 span 的引用。节点之间的连线表示的 span 和它的父 span 直接的关系。在上面的图里,每一个 Span 都记录了调用的接口名、parent id 和自身 id。Dapper 里这些 id 是全局唯一的 64 位整数,在其他一些分布式链路跟踪系统里,parent id 和 span id 一般是合并成一个字符串表示:

-0
--0.1
---0.1.1
---0.2.2
--0.2
---0.2.1

比如 spanId = 0.1 表示该 span 的父节点的 spanId 是 0,spanId = 0.1.1 表示该 span 的父节点是 0.1。

下面是是一个 span 的内部细节图,除了 spanName、spanId,还记录了 client 端和 server 端开始和结束的时间,

分布式链路跟踪系统(一):Dapper 介绍_第3张图片

Annotation

Dapper 还允许开发人员在 span 里添加额外信息以监控更高级别的系统行为,或添加调试信息。annotation 有两种:纯文本、key-value 对。在分布式链路跟踪系统里,不仅可以根据 traceId 查询链路信息,也可以根据 key=value 表达式来查询关联的 trace 链路。比如,在交易业务中,使用 key/value 记录订单号时,就可以根据订单号来查出相关的一系列 trace 链路,这对于问题的排查是很有帮助的。

植入

如何在 RPC 调用时传递 trace 信息,如何上报收集的数据呢?Dapper 号称对应用开发者近乎零侵入,主要是依赖于对通用组件库的改造,这要求公司内部使用统一的 RPC 框架等。改造方法如下:

  1. 系统内部,跟踪上下文放在了 ThreadLocal 里。
  2. 通过线程池异步执行时,对线程池进行包装,将 ThreadLocal 从主线程传递到子线程里。对于回调模式也是类似的操作。
  3. 对于 RPC 通信,修改 RPC 框架,把 traceId、spanId 放在 Context 里进行传递。

采样率

trace 数据的收集和上报是会耗费一定的系统资源的,如果系统对性能要求比较高,可以不全量采集上报,设置一个采样率,只采集部分数据,也是可以帮助我们分析系统问题的。

资料

  1. Dapper,大规模分布式系统的跟踪系统
  2. Dapper, a Large-Scale Distributed Systems Tracing Infrastructure

你可能感兴趣的:(分布式)