tail-based sampling 实战关键请求保留普通请求自动降噪我以前也以为链路追踪这件事采得越多越安心。直到有一次值班Jaeger 查一条慢请求要转十几秒ES 磁盘还在疯狂涨。那天我才彻底接受一件事全量追踪不是安全感很多时候只是把噪声原封不动地存了下来。这篇想聊一个更实用的思路别再只靠固定比例采样了直接把 tail-based sampling 用起来。核心目标不是“少存点数据”这么简单而是把真正该留下来的关键请求保住把普通请求自动降噪。为什么固定比例采样经常不够用很多团队上采样的第一步都是把 head sampling 设成 10% 或 20%。这样做当然能立刻降成本但问题也很明显请求一进系统就被决定命运了。如果一条请求刚好没被采到后面哪怕它超时、重试、报错整条 trace 还是看不到。真正出事故时最糟糕的不是数据太多而是关键请求偏偏没留住。我后来把问题拆得更直白一点普通成功请求可以少看但异常请求、慢请求、关键业务请求必须尽量保住。只要目标变成这个tail sampling 就比单纯的概率采样更顺手。tail-based sampling 到底解决了什么tail sampling 的思路很像“看完整张卷子再打分”。Collector 不会在请求刚进来时立刻决定保不保留而是先等一小段时间把整条 trace 尽量收齐再根据结果做判断。这样你就能按结果留数据而不是按运气留数据。比如状态码是 5xx 的请求全留耗时超过 1.5 秒的请求全留支付、下单、登录这类关键链路高比例保留健康检查、静态资源、低价值轮询直接过滤或低比例采样这个差别看起来只是“决策时机”变了实际效果却很大。以前是先丢再后悔现在是先观察再筛选。我更推荐的落地方式head sampling tail sampling 配合用只开 tail sampling 也不是万能的。因为它要先缓存一段时间的 trace如果入口流量本来就特别大Collector 的内存和队列压力会先上来。所以我更推荐两段式做法。第一层在入口先做基础过滤。像/healthz、/metrics、内部心跳、静态资源这类低价值流量能不进追踪系统就别进。第二层对普通在线请求做一层温和的 head sampling先把洪峰削下来。第三层再用 tail sampling 专门兜住异常、慢请求和高价值业务请求。这个思路的好处很现实不是把所有流量都塞给 tail sampling 硬扛而是先把确定没价值的噪声挡掉再把真正重要的样本挑出来。一套比较稳的 Collector 配置思路下面这份配置不一定适合所有团队但很适合作为第一版起点processors:filter/drop-noisy-spans:error_mode:ignoretraces:span:-attributes[http.target] /healthz-attributes[http.target] /metricsprobabilistic_sampler/default:hash_seed:22sampling_percentage:20tail_sampling:decision_wait:10snum_traces:50000expected_new_traces_per_sec:3000policies:-name:keep-errorstype:status_codestatus_code:status_codes:[ERROR]-name:keep-slow-requeststype:latencylatency:threshold_ms:1500-name:keep-core-servicestype:string_attributestring_attribute:key:service.namevalues:[payment-service,order-service,auth-service]-name:sample-the-resttype:probabilisticprobabilistic:sampling_percentage:5这里最关键的不是参数本身而是顺序。先过滤噪声再做基础削峰最后保关键样本。只要顺序反过来系统压力和样本质量通常都会变差。这几个参数最容易配错1.decision_wait太短如果链路里有异步任务、消息队列或者跨多个服务的调用3 秒、5 秒这种配置经常不够。Collector 还没等到完整 trace就已经提前做决定了结果是慢请求明明很关键却被当成普通请求放掉。我的经验是先按真实链路时长给 8 到 15 秒再看内存和命中率慢慢调。别一上来追求极限。2.num_traces太小这个参数太保守高峰期就会把旧 trace 挤掉。表面上策略开着实际关键链路留不住。简单估算方法可以先按“峰值每秒新 trace 数 ×decision_wait秒数”来抓一个大致量级再结合 Collector 内存曲线验证。3. 只盯报错不盯慢请求很多线上问题不会直接 500而是先慢、再重试、最后级联放大。如果策略里只有 error没有 latency排障窗口会直接少一半。我怎么看一套采样策略有没有真的跑稳我现在不会只看“存储降了多少”而是同时看三组结果。第一组是成本每天 trace 存储量、索引增长速度、Collector 导出吞吐。第二组是体验Jaeger 查询耗时、trace 搜索成功率、Collector 队列堆积。第三组最重要是故障复盘时能不能稳定找到关键 trace。如果成本降下来了但真正出事时 trace 老是缺关键 span那这套策略只是省钱不算可用。反过来如果异常请求和慢请求都能稳定保住普通噪声又显著下降这才说明策略开始有工程价值。写在最后我后来越来越少说“全量追踪更保险”这种话了。真正靠谱的可观测性不是把所有请求都留着而是在你最需要证据的时候最快看到最该看的那一批请求。tail-based sampling 的价值就在这里。如果你现在也被 trace 成本、查询变慢、样本噪声太多这些问题困住真可以先别纠结采样率数字先把“哪些请求必须留下来”这件事定义清楚。后面的策略反而会简单很多。