图 2:5 个 span 在 Dapper 跟踪树种短暂的关联关系
在 图 2 中说明了 span 在一个大的跟踪过程中是什么样的。Dapper 记录了 span 名称,以及每个 span
的 ID 和父 ID,以重建在一次追踪过程中不同 span 之间的关系。如果一个 span 没有父 ID 被称为 root
span。所有 span 都挂在一个特定的跟踪上,也共用一个跟踪 id(在图中未示出)。所有这些 ID 用全
局唯一的 64 位整数标示。在一个典型的 Dapper 跟踪中,我们希望为每一个 RPC 对应到一个单一的
span 上,而且每一个额外的组件层都对应一个跟踪树型结构的层级。
图 3:在图 2 中所示的一个单独的 span 的细节图
图 3 给出了一个更详细的典型的 Dapper 跟踪 span 的记录点的视图。在图 2 中这种某个 span 表述
了两个“Helper.Call”的 RPC(分别为 server 端和 client 端)。span 的开始时间和结束时间,以及任何 RPC
的时间信息都通过 Dapper 在 RPC 组件库的植入记录下来。如果应用 程序开发者选择在跟踪中增加
他们自己的注释(如图中“foo”的注释)(业务数据),这些信息也会和其他 span 信息一样记录下来。
记 住,任何一个 span 可以包含来自不同的主机信息,这些也要记录下来。事实上,每一个 RPC span
可以包含客户端和服务器两个过程的注释,使得链接两个主机的 span 会成为模型中所说的 span。由
于客户端和服务器上的时间戳来自不同的主机, 我们必须考虑到时间偏差。在我们的分析工具,我
们利用了这个事实:RPC 客户端发送一个请求之后,服务器端才能接收到,对于响应也是一样的(服
务器先响 应,然后客户端才能接收到这个响应)。这样一来,服务器端的 RPC 就有一个时间戳的一
个上限和下限。
2.2 植入点
Dapper 可以以对应用开发者近乎零浸入的成本对分布式控制路径进行跟踪,几乎完全依赖于基于少
量通用组件库的改造。如下:
当一个线程在处理跟踪控制路径的过程中,Dapper 把这次跟踪的上下文的在 ThreadLocal 中
进行存储。追踪上下文是一个小而且容易复制的容器,其中承载了 Scan 的属性比如跟踪 ID
和 span ID。
当 计算过程是延迟调用的或是异步的,大多数 Google 开发者通过线程池或其他执行器,使