把断掉的追踪接起来
目标
跟踪只要有一处没有接上,整条就完全没用了。而且断开时不会报错,所以在打开仪表板看之前,没有人会知道。
本实验会给你三个已经断开的服务,让你把它们接起来。
开始
cp /opt/lab/trace/* . && chmod +x run.sh
./run.sh # a → b → c 로 요청 하나를 흘린다
python3 tree.py # 이어졌는지 본다
文件
| 文件 | 作用 |
|---|---|
svc.py |
单个服务。其中有一个 bug |
run.sh |
启动三个服务并发送一个请求 |
tree.py |
读取日志,判定是否已经接上 |
需要了解
run.sh 在终止服务时不使用 pkill -f svc.py。这个匹配模式也会命中运行该脚本的 shell 的命令行,从而把自己杀掉。它改为记下 PID,只终止这些进程。
traceparent
00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
│ │ │ │
│ trace id (16바이트) 부모 span 플래그
버전
步骤
- 确认跟踪断开 →
01-broken.txt - 在哪里、为什么断开 →
02-where.md - 把它接起来 → 由评分器亲自运行来确认
- 读懂格式 →
04-format.md - 采样一致性 →
05-sampling.txt - 并发请求 →
06-concurrent.txt - 总结 →
07-notes.md
亲眼看到断开的跟踪
把 /opt/lab/trace/ 复制到工作目录,运行 ./run.sh,并把 python3 tree.py 的结果保存到 01-broken.txt。
从 cp /opt/lab/trace/* . && chmod +x run.sh 开始。一个请求会流经三个服务(a→b→c)。
症状与真实现场完全一样——每个服务都在正常发送跟踪数据,但它们并没有连起来。仪表板上会堆满只有一个跨度的跟踪。
指出在哪里、为什么断开
阅读 svc.py,在 02-where.md 中写出问题出在哪一行,并说明为什么这一行会让跟踪断开。
看一看向下一个服务发送请求的位置。接收方发现没有请求头时,会新建一个跟踪 ID——这是正确的行为。问题出在发送方。
跟踪断开的位置几乎总是在调用方。无论怎么看接收方的代码,都找不到原因。
把它们接成一条
修改 svc.py,让三个服务共享同一个跟踪 ID,并且父子关系相连。
在发出的请求上加上 traceparent 请求头。格式为 버전-trace-내span-플래그(占位符依次为版本、跟踪 ID、自己的跨度、标志位)。放在父级位置的不是收到的父跨度,而是当前自己的跨度——这里很容易出错。
评分器会亲自运行,确认跟踪 ID 只有 1 种、根只有 1 个、找不到父级的跨度为 0 个。
把 traceparent 拆开来读
在 04-format.md 中写出 traceparent 的四个部分各自是什么,并以第 3 步日志中的一个实际值为例。
00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01。从前往后依次是版本、跟踪 ID(16 字节)、父跨度(8 字节)、标志位。
长度是固定的,所以肉眼也能验证——跟踪 ID 如果不是 32 个字符,当场就能判定有错。
采样只决定一次
确认即使根服务以标志位 00(不采集)起始,三个服务留下的也是相同的标志位,并把结果保存到 05-sampling.txt。
决定只在根处做一次,然后原样往下传递。中途重新决定,跟踪就会变成半条——前半部分被采集、后半部分缺失的跟踪,对调试的妨碍无出其右。
在根处更改起始标志位后运行,并保存 tree.py 输出中的标志位那一行。
同时发送多个请求时会不会混在一起
同时发送三个请求,确认每个请求都各自构成完整的跟踪,并把结果保存到 06-concurrent.txt。
参考 run.sh 启动服务后,用 & 同时发送三个 curl。结果正确时,跟踪 ID 有 3 种,每条跟踪有 3 个跨度,根有 3 个,孤儿为 0 个。
这里出问题的典型原因是把上下文放进全局变量。用一个请求测试时一切正常,流量一上来,跟踪就会相互混在一起。这就是每种语言都有按请求存储的机制的原因。
总结三点
在 07-notes.md 中至少写三行:跟踪断开的位置、父级位置放什么、采样决定在哪里做。
正文中必须包含 호출、부모、샘플링。