当链路追踪的数据量开始拖慢应用时,你首先想到的可能是“全量采集”。但全量采集往往带来两个问题:存储成本飙升,以及追踪本身的性能开销。本文不讨论“要不要采样”,而是直接探讨“采样策略”如何选:头部采样、尾部采样、概率采样各自解决什么问题,又有什么代价。
性能与可观测性的冲突从何而来?
链路追踪需要为每个请求生成 trace,包含多个 span。在高并发场景下,每秒可能产生数十万条 span。如果不加控制,采集器、存储和查询都会成为瓶颈。更关键的是,追踪的“埋点”本身也有开销——生成 span、附加上下文、导出数据,这些操作会占用 CPU 和内存。Prometheus 官方文档指出,监控系统需要高效地处理时间序列数据,而追踪系统同样面临数据规模带来的挑战。
采样策略的核心:保留哪些数据?
采样的本质是“有选择地保留数据”。常见策略包括:
- 头部采样(Head-based sampling):在请求开始时决定是否采集。优点是简单,但可能错过后期才出现的错误。
- 尾部采样(Tail-based sampling):等请求结束后再决定。能根据结果(如错误、延迟)精准保留,但需要缓冲所有 span,内存开销大。
- 概率采样(Probabilistic sampling):按固定比例(如 10%)随机采集。实现简单,但无法保证覆盖关键请求。
选择哪种策略,取决于你的目标:是排查错误,还是分析性能趋势?
头部采样:简单但可能漏掉关键数据
头部采样在请求入口处决定是否采集,通常基于请求 ID 的哈希或随机数。它的优势在于开销低,因为不需要缓存整个 trace 的 span。但问题也很明显:如果请求在后期失败,而你只采集了 1% 的流量,很可能漏掉这个错误。OpenTelemetry 官方文档提到,它支持多种采样策略,其中就包括头部采样,但建议根据具体场景权衡。
尾部采样:更智能但代价高
尾部采样在请求结束后,根据结果(如状态码、延迟)决定是否保留。它能精准捕获错误和慢请求,但代价是必须缓存所有 span 直到请求完成。在高并发下,内存占用可能非常大。一种折中是“混合采样”:对普通请求用概率采样,对错误请求强制采集。
概率采样:简单可靠但缺乏针对性
概率采样是最常见的策略,比如固定采集 10% 的请求。它的优点是实现简单、开销可控,适合流量大但不需要精确排错的场景。但如果你需要排查某个特定用户的问题,概率采样可能无法覆盖。OpenTelemetry 的 SDK 内置了概率采样器,你可以通过配置调整采样率。
如何选择采样策略?
没有“最佳”策略,只有“适合”的策略。以下是一些判断依据:
- 流量规模:流量越大,采样率越低,但需要确保关键请求不被漏掉。
- 排错需求:如果经常需要排查线上问题,尾部采样或混合采样更合适。
- 存储成本:采样率越低,存储成本越低,但可观测性也越弱。
你可以从概率采样开始,逐步调整,观察错误捕获率和性能开销的变化。
常见误区
误区一:采样率越高越好。实际上,高采样率可能拖垮性能,反而影响可观测性。误区二:忽略采样对聚合指标的影响。如果采样不均匀,基于 trace 的指标(如错误率)可能失真。误区三:认为采样策略可以一劳永逸。随着业务变化,需要定期评估。
实践建议:从 OpenTelemetry 开始
OpenTelemetry 提供了灵活的采样配置,你可以在 SDK 中设置采样率,也可以通过 Collector 进行集中式采样。建议先在测试环境验证不同策略的采样效果,再逐步应用到生产。同时,结合 Prometheus 等监控工具,观察系统性能指标,确保采样本身不成为瓶颈。
参考资料
延伸阅读
