LabHub
学习 学习路径 课程

分布式链路断掉的地方

决定丢掉什么的那件事

在 LabHub 中继续学习

一句话总结

取样不是减少成本的装置,而是决定看什么的设计。如果定错了,就没有实际需要的线路。

流程图: 减少成本的装置,而是决定看什么的设计 · 没有那个请求的痕迹的可能性是99% · 在头部减少1020% · 错误是100%

为什么需要这个?

每个请求都会产生数十个范围。如果每秒有1000个请求,一天就有数十亿个范围。如果全部存储的话,存储成本会超过应用程序成本。

但是如果随意留下1%,在出现障碍时,没有那个请求的痕迹的可能性是99%。所以采样不是从“要留下多少”入手,而是从“一定要留下什么”入手。

三种方式

方式 什么时候决定 优点 代价
请求开始时 便宜简单,传播容易 不能只选择慢请求
尾部 完成跟踪后 准确选择错误·慢速 要收集范围,太贵了
延迟限制 每秒N个上限 即使狂奔也不会增加费用 狂奔路段的样本会减少

实际组合一般是这样的。

  1. **在头部减少10~20%**的基本线条
  2. **错误是100%**强制(traceparent打开的样本标志传播)
  3. 只对重要的端点进行尾采样,以减少延迟。

采样决定需要传播。

这是在这里最容易出错的地方。采样必须以轨迹单位来确定, 如果每个服务单独设定的话,痕迹就会碎裂。

프런트(20%) → API(20%) → 결제(20%)

각자 정하면 세 서비스가 모두 남길 확률 = 0.2³ = 0.8%
→ 완전한 트레이스는 거의 안 남고, 조각난 스팬만 쌓인다

W3Ctraceparent头部的最后一个字节是样本标志。在前面一圈 做出决定后,后面只需要遵守那个决定

traceparent: 00-4bf92f...36-00f067aa0ba902b7-01
                                              ↑ 01 = 샘플됨, 00 = 아님

OpenTelemetry SDK的ParentBased(root=TraceIdRatioBased(0.2))实现这个。 有父母的话,就按照父母的决定,没有父母的时候(是根的话)才掷20%的骰子。 TraceIdRatioBased只要使用就会在每个服务中单独滚动,出现上述0.8%的问题。

TraceIdRatioBased为什么不是随机,而是用trace ID的哈希来确定,原因就在这里。 有。相同的trace ID无论在哪个服务中计算都会得到相同的答案,所以设置 如果一样的话,决定就会自动一致。

100%留下错误的方法

“把错误都留下”这句话虽然容易,但在头采样中是不可能的。请求开始 因为不知道什么时候它会失败。有两种绕行路线。

**应用程序打开标志。**检测到错误时,强制记录当前范围 标记为目标。虽然无法恢复已经过去的父母范围,但下面还有剩余。

**使用尾部采样。**收藏家在看到整个痕迹后进行判断,所以很准确。 政策是这样的样子。

tail_sampling:
  decision_wait: 10s
  policies:
    - name: errors            # 오류는 전부
      type: status_code
      status_code: {status_codes: [ERROR]}
    - name: slow              # 2초 넘는 것은 전부
      type: latency
      latency: {threshold_ms: 2000}
    - name: baseline          # 나머지는 5%
      type: probabilistic
      probabilistic: {sampling_percentage: 5}

政策会被评价为OR——只要有一点正确就留下。

尾采样隐藏的成本

收藏家把整个痕迹都收集到内存中后进行判断。所以出现了两种情况。

如果不知道这两种情况,打开尾采样,则采集器会死于OOM,死去的过程中,整个跟踪会消失。

常见的误解

“提高采样比例会更准确” — 指标不应该与采样无关。请求数、错误率、延迟是指标,跟踪是“查看该请求在哪里花费了时间”的工具。如果通过跟踪计算比例,采样偏差就会被保留。

“只要留下错误就行”——不是错误,而是慢请求会提供更多信息。错误虽然也会在日志中留下,但正常响应却花了3秒的请求,如果没有跟踪,就无法解释。

在实际工作中真正重要的东西

采样决定必须在前面一个人下一次,然后传播到最后。如果中间服务根据自己的判断重新确定,则只剩下一半的轨迹。

traceparent的最后标志(01/00)承担了那个决定。自动计量会监控这个,但直接制作HTTP客户端的代码如果重新写头,那么从那个点开始决定就会被初始化。