OpenTelemetry

OpenTelemetry 是一个开源项目,旨在通过统一的工具集、API和SDK,简化在多样化的技术栈中集成可观测性功能,确保一致地收集、处理及导出应用性能数据。

Distributed Tracing关键技术-常见采样技术概览

陈陈

采样是Tracing系统的关键技术之一,在Tracing领域的第一篇论文《Dapper, a Large-Scale Distributed Systems Tracer》中提到,为了避免对业务系统产生极大的存储压力,Google运用了各种采样策略来降低Tracing系统产生的数据。随着多年的发展,在今天的Tracing系统中,埋点越来越密集,附着在Span中的数据也越来越丰富,进而导致,整个Tracing系统作为一个监控旁路所占的额外CPU、内存、网络IO开销也逐渐增长,一定程度上影响到了业务稳定性。

综上,不管是从Tracing系统本身的成本、稳定性来说,还是从业务系统的稳定性来说,采样都是Tracing系统的关键的技术之一。Tracing系统的采样技术相比于传统的采样,还有一个绕不开的话题,即如何保证链路完整性,比如对于一条跨多个应用的链路A->B->C,采样后是否能保证链路完整。

围绕Tracing采样,近些年工业界和学术界都提出了各种各样的采样算法。这些采样算法大体可分为两类,分别是头采样算法和尾采样。下面对这些采样的概念以及涉及到的技术做一个简单介绍

头采样

头采样是一种在链路开始的位置决定是否采样的采样策略,大体可分为两类,一类是固定比例采样,一类是固定流量采样。

固定比例采样

顾名思义,固定比例采样即按照一定比例对链路进行采样,取固定比例的算法比较多,常见的有两种:

  • 数值取模:即通过一个数值进行取模运算看是否等于0,比如想要实现10%采样,则只需要对10取模,想要实现1%采样,则只需要对100取模。比如,在开源探针Pinpoint中,是维护一个全局递增计数器,每次有新请求到来,则计数器加1,然后对采样比例取模,最终实现固定比例采样
  • 数值范围判断:即判断一个数值是否位于一个子数值区间范围内,完整数值区间一般取Long型整数的最小值与最大值,即[Long.MIN_VALUE, Long.MAX_VALUE],当需要实现10%采样,则子数值区间范围为[Long.MIN_VALUE, Long.MAX_VALUE * 0.1], 当需要实现1%采样时,则子数值区间范围为[Long.MIN_VALUE, Long.MAX_VALUE * 0.01]。比如在Jager、Zipkin、Opentelemetry中均是采用类似的实现,他们的TraceId往往包含一个随机生成的long型整数,通过判断该整数是否在子区间来实现固定比例采样
固定流量采样

即在每个时间窗口采样固定数量样本,一般采用令牌桶算法,该算法较为经典,有较多参考资料,此处不再赘述。

如何保证链路完整

头采样往往能够保证链路完整,他们保证链路完整的方式主要有两种:

  • 传递采样标:是现在比较主流的方案,即在跨进程通过header传递trace上下文的同时传递该条trace是否采样的标识,现在主流的Tracing协议比如W3C、Zipkin、Jaeger在协议头中都支持该字段。
  • 全局共识:一般是在整个系统中设置一个全局的采样比例,且在整个分布式系统中大家都遵循一个统一的规则来判断一条trace是否要采样。举个例子,在阿里巴巴内部的Tracing系统EagleEye中,为了实现全局1采样链路完整,有一个全局共识,当TraceId中第三部分顺序号取值为000时,则该条trace要采样。下图是一个EagleEye系统的traceId组成示意图

尾采样

尾采样原本是统计学中一个概念,特指从一堆样本中挑选分布于尾部的样本,即一些出现频率很低的样本。对应到Tracing领域,尾采样特指一些能够保证命中一些出现概率较小的样本(一般是一些错慢链路)的采样策略,按照采样策略运行在服务端还是数据采集端,分为服务端尾采样和客户端尾采样

服务端尾采样

服务端尾采样的策略一般依赖客户端数据全量上报,在服务端对数据进行二次分析,对满足指定特征的数据进行采样。学术界基于一些机器学习算法在这方面做出了很多前沿的研究。但是考虑到实际应用的复杂度、成本以及不确定性等原因,目前工业界做的较为成熟的还是错慢采样以及基于用户自定义规则的采样。

服务端尾采样的另外一个技术挑战是如何保证前文提到的链路完整。在服务端集群部署的场景下,一条trace的多个span当且仅某个span满足尾采样需求时,如何保证其他span也能保存下来。目前业界常见的做法有两种:

  • traceId广播: 即当服务端集群中某个节点发现span异常时,广播该traceId到其他节点,其他节点收到后即保存该traceId关联的span
  • traceId路由:即在数据处理前做一次数据路由,将相同traceId的数据路由至相同处理节点,这样就能保证一个链路的所有span均在一个节点上处理,也就能保证链路完整。

上述两种方案由于都涉及到数据憋内存,所以只能保证正常调用的链路完整。当遇到一些长尾调用时,无法保证链路完整。

客户端尾采样

由于服务端尾采样仅降低了最终的存储成本,并未降低端侧开销,目前业界也有不少对于客户端尾采样的研究:

  • 单节点尾采样:该方案忽略链路完整性需求,仅在单节点做尾采样,对于问题的诊断也有一定的价值
  • 基于采样标回传的尾采样:该方案在某节点的span满足尾采样条件时,通过response header中回传采样标,让上游span以及后续span能保存下来,一定程度上能部分解决单节点尾采样链路完整性的问题。
  • 基于节点间协作的尾采样:该方案和服务端尾采样的traceId广播方案类似,只是将整个广播的范围下层到了所有客户端,值得注意的是,2022年一篇名为《The Benefit of Hindsight: Tracing Edge-Cases in Distributed Systems》的论文中通过完备的实验论证了该方案的可能性,有兴趣的可以看一下该论文。

总结

Trace的采样技术经过十多年的发展演进,除了上述介绍的以外还有很多新奇的做法,甚至跳出了上述的头采样、尾采样的范畴,本周篇幅有限,未做完备介绍,仅对一些较为主流的采样方案做了介绍。


observability.cn Authors 2024 | Documentation Distributed under CC-BY-4.0
Copyright © 2017-2024, Alibaba. All rights reserved. Alibaba has registered trademarks and uses trademarks.
浙ICP备2021005855号-32