Trace 采样策略:别等事故来了才发现没证据
Trace 采样策略:别等事故来了才发现没证据
一、全量 Trace 太贵,零 Trace 太盲
后端可观测性里,Trace 是排查链路问题的关键证据。通过分布式追踪,你能看到一次请求经过了哪些服务、每个服务花了多少时间、哪个环节产生了延迟。但全量采集 Trace 成本非常高——存储、索引和查询都对基础设施有压力。反过来,如果把采样率设得太低,事故发生时可能恰好没有保留相关样本,等于没有证据。
我经历过一次非常尴尬的排查场景:用户投诉某个核心接口响应超过 8 秒,而正常情况下这个接口只需要 200ms。我们打开 Trace 面板想查链路,发现该接口的采样率只有 2%,而故障时段没有任何 span 被采到。日志里只有"请求完成"和总耗时,但完全看不出时间花在了哪个下游。最后是手动在生产环境加了临时日志重新部署,才定位到问题——一个下游 API 的 DNS 解析耗时 6 秒,而 DNS 层有缓存且平时解析正常,只在缓存意外失效时才出现。这个问题本可以在 5 分钟内通过 Trace 定位,但因为采样策略不对,浪费了一整天。
采样策略要和业务风险绑定。核心接口、错误请求、慢请求和高价值租户,应该有更高的采样率。普通成功请求可以低采样。采样不是"平均撒胡椒面",而是有选择地在高风险位置保留证据。
二、采样应该分层
flowchart TD A[请求进入] --> B{是否是错误请求} B -->|是| C[强制采样 100%] B -->|否| D{是否慢请求 > P95} D -->|是| C D -->|否| E{是否核心接口} E -->|是| F[高采样率 20%] E -->|否| G[基础采样率 5%] C --> H[写入 Trace 存储] F --> H G --> H入口做基础概率采样覆盖正常流量,服务内部对异常和慢请求做强制采样。还有一种叫"尾采样"的方法——在请求完全结束后根据结果决定是否保留 span。错误请求 100% 保留,正常请求低概率保留。尾部采样的好处是不会漏掉任何异常,但缺点是需要缓冲 span 增加内存开销。对大多数团队来说,先把错误请求和慢请求的强制采样做好,收益已经非常明显。
采样策略还要考虑多服务链路。一个请求可能经过 5 个微服务,如果入口的采样决策能传播到下游(通过 trace context header),所有服务对同一条 trace 保持一致的采样决策,排障时看到的才是一条完整链路而不是断断续续的片段。
三、Trace 字段要克制且结构化
Trace 里不要塞完整的请求体、用户隐私信息和长文本答案。可观测性不是数据湖,字段要能定位问题同时避免泄露。常用做法是记录业务标识的 hash、数据长度、枚举状态码、资源 ID 等可统计但不敏感的信息。采样配置要支持热更新,不重启服务就能临时提高某个接口的采样率。事故处理期间把出问题接口的采样率提到 100%,事故恢复后再降回正常值。每次调整都要留审计记录——谁调的、为什么调、什么时候调的、什么时候恢复。
四、低采样率下也要能排查
低采样场景下,日志、指标和 Trace 三者要能互相跳转。日志条目里带 trace_id,指标的标签能定位到 route 和状态码,Trace 能展示关键下游的调用耗时和返回码。三者割裂的话,采样再高排查也费劲。关键错误事件(支付失败、权限拒绝、消息重复消费)即使请求未被采样,也应该写独立的审计日志。
Trace 采样还要覆盖异步链路。请求写入消息队列后的消费者处理可能在另一个进程甚至另一个时间窗口执行。需要把 trace context 写进消息头,让消费者能延续同一条链路。否则 Trace 在队列入口就断了,接口看起来很快但真正的耗时藏在后台消费里。跨服务的 Trace 传播要做兼容检查,不同语言 SDK 可能使用不同的 header 标准(W3C TraceContext vs B3 vs Zipkin)。统一传播标准能避免跨服务 Trace 断裂。
Trace 数据的保留策略也需要分层:普通 Trace 短期保留节省成本,事故 Trace、错误 Trace 和审计相关 Trace 延长保留以便复盘。存储成本有限时,优先保留能解释用户影响的链路,而不是平均保留所有请求。
采样还应该留一小部分"随机样本"——不按规则筛选,完全随机保留 0.1% 的请求。这些样本可以用来发现那些"看起来正常但实际有隐性问题"的请求,比如虽然没报错但内部有多次重试、降级或长时间等待。随机采样是发现未知问题的最后一道防线。
五、总结
Trace 采样策略要分层设计:对错误、慢请求和核心接口提高采样率,对普通成功请求用低采样控制成本。字段设计要克制避免泄露隐私,配置支持热更新和审计。可观测性的价值不在于收集所有数据,而是在事故发生时能留下足够可信、足够完整的证据链。好的采样策略让排查者不需要祈祷"刚好采到那条请求",而是让每一条可能出问题的请求都被保留下来。