多服务分布式追踪设计
区分 request ID 关联与 W3C trace context 传播,说明跨服务 span、SSE 生命周期、采样和恢复标识的边界。
[!info] related notes
- 所属 MOC: BodySense MOC
- 可观测性: AI 服务可观测性
- 架构: 多服务架构, 多服务 SSE 管道
- 健康检查: 健康检查端点
多服务分布式追踪设计
范围
以 React → Go → Python 的 AI 服务为例,定位检索、模型调用和流式转发的等待与失败。这里描述设计原则,不证明 BodySense 当前部署已实现完整追踪。
先区分三种身份
| 标识 | 职责 | 边界 |
|---|---|---|
| request / correlation ID | 关联一次请求的日志或用户报障 | 自定义 X-Request-ID 不会自动成为 OTel trace context |
| trace ID / span ID | 标识一次追踪及其中的执行片段 | 同一 trace 可包含多个父子 span;每个 span 有自己的 ID |
| run ID / event sequence | 关联业务任务、事件顺序和恢复位置 | 同一 run 可跨多个请求与 trace;trace ID 不能代替恢复游标 |
使用 W3C Trace Context / OpenTelemetry
traceparent 包含版本、trace ID、父 span ID 与标志;不是只传一个 trace ID 字符串。具体提取、校验和注入交给所用 OTel instrumentation / propagator。
React(可选 Web instrumentation)
→ 请求携带 traceparent
Go 入口:提取 context → 创建 server span
→ 下游 client span → 注入当前 context
Python 入口:提取 context → 创建 server span
→ rag_retrieval / llm_generation 等子 span
- 没有合法上游 context 时,由入口按策略创建新 trace;前端不必总是生成。
- 给 span 添加
trace_idattribute 不会改变它的父子关系或真实 TraceID。 - request ID 和 trace context 都不是身份凭证,不能用于绕过鉴权;跨信任边界需校验或按策略重新建立 context。
- 后台 worker 或消息队列需要显式传递 context,或用 span link 关联;不能依赖同步请求上下文自动存活。
- 浏览器跨域传递或读取额外头部时,还需符合 CORS 配置。
SSE 的生命周期
连接建立不代表模型已输出,HTTP 200 也不代表 run 已成功。记录流开始、首个有效输出、正常完成、取消请求、确认取消和异常断开。
覆盖流转发的 span 必须存活到流处理结束;不能在返回异步生成器时就提前结束。异常路径也要结束 span、关闭上游响应并清理订阅。
事件可通过响应头、连接上下文或事件字段关联 trace;不要求每个 token 都带 trace ID。代理不得为了加字段破坏 event、id、多行 data 与空行分帧。重连后新 trace 可关联原 run;业务恢复参见 durable-sse-recovery-with-after-seq。
不要为每个 token 建 span 或无界记录 payload。可以记录首输出时间、事件计数、最后游标与结构化终止原因;这些诊断字段不等于完整事件日志。
导出与采样
Go、Python 和可选的 Web instrumentation 创建 span,再按配置通过 OTLP exporter / Collector 送到 Jaeger、Tempo 等后端。HTTP 业务调用负责 context 传播,OTLP 负责遥测导出,两条路径不同。
采样比例按流量、预算与排障需要设置,没有通用的 10%~20% 标准。Head sampling 在请求开始时通常不知道最终是否失败;若希望优先保留错误 trace,需要相应的 tail sampling 或其他采集设计,仍受采集范围、缓存与丢弃策略限制,不能承诺错误 trace 永远完整。
最小日志关联方案
尚未接入 OTel 时,可以先维护 request ID:
- 入口生成或验证受限长度 / 格式的 correlation ID。
- 下游请求透传该 ID,各服务结构化日志记录它。
- 需要时通过响应头返回,让前端报障能提供相同 ID。
- 记录阶段、耗时、结果与业务 run ID,再通过日志搜索关联。
这能帮助定位,但没有 span 父子关系、采样和完整调用树。不要把 correlation ID 命名为 trace ID 后就声称已完成分布式追踪,也没有“解决 80% 排障问题”的通用保证。
验证
- 同一请求跨 Go / Python 后,检查真实 span context 的 trace ID 与父子 span 关系,而非只看日志字段相同。
- 不携带 / 携带非法 context、下游超时、流中断时仍有合理终态与资源释放。
- 模拟重连:新连接可定位到原 run,不重复业务副作用,event sequence 保持恢复语义。
- 在实际采样配置下检查缺失片段,并区分未采样、导出失败和代码未埋点。
- 日志与属性避免采集凭据、完整对话或敏感业务 payload;ID 也须按访问和保留策略管理。
来源
- W3C Trace Context:
traceparent格式与跨进程传播。 - AI 服务可观测性设计:模型、token、质量与流式指标。