消息轨迹能解决哪些排障问题?
简化版
消息轨迹把生产、Broker 接收/存储、投递、消费尝试和业务结果按 eventId 串起来,可定位消息停在哪一段、是否重复、为何进死信以及端到端延迟。它是诊断证据,不等于消息一定未丢,也不能替代业务对账。
详细版
统一记录 eventId、traceId、Topic、脱敏 key、partition/offset、producer、consumer group、attempt、时间戳和结果码。生产 span 与消费 span 往往跨越很久,使用 span link 或消息传播上下文关联,避免构造一个持续数天的父子调用栈。
采集要兼顾完整性、成本与隐私:错误和死信全量,成功链路按策略采样,关键生命周期事件落审计存储;禁止把完整 payload 和敏感 ID 当普通标签。排障最终结合 Broker 位点、消费者日志和业务数据库验证。
完整版教学
一、消息链路有哪些阶段
一次业务通常经过应用创建、生产发送、Broker 确认、持久化、分区投递、消费者拉取、业务处理和位点提交。只看生产日志的“发送成功”,无法判断后六段发生了什么。
记忆钩子:轨迹回答“走到哪、停在哪、重复几次”,业务库回答“最终做成没有”。
二、最小字段集合
| 字段 | 用途 | 注意 |
|---|---|---|
| eventId | 跨阶段主键 | 重试必须稳定 |
| traceId | 关联业务请求 | 可跨异步传播 |
| partition/offset | Broker 定位 | 分区内有效 |
| group/attempt | 消费诊断 | 多组独立 |
| timestamps | 延迟拆分 | 使用统一语义 |
payload 通常只存摘要或受控引用,避免隐私泄露和索引膨胀。
三、怎样拆端到端延迟
produce_delay = broker_ack - app_created
queue_delay = consume_start - broker_stored
process_delay = consume_end - consume_start
total_delay = consume_end - app_created
例如总延迟 12 秒,其中排队 10 秒、处理 100ms,优化消费者并发比优化业务代码更有效。跨主机时间戳需要校时并评估时钟误差;单调时钟只适合计算同一进程内的耗时,不能直接在不同机器之间相减。
四、重复与丢失如何定位
同 eventId 多次生产记录说明发送重试;一次生产、多次消费 attempt 说明消费重投;Broker 有存储记录但目标组无投递,检查订阅和位点;业务库成功但 ACK 失败,后续重试应命中幂等。
“轨迹查不到”不等于消息未发送,采样、采集器故障或索引过期都会造成观测缺口,因此关键业务仍需 Outbox 和对账。
排查疑似丢失时应做三方交叉:源端确认 Outbox/发送事实,Broker 核对分区位置与保留边界,消费端检查提交位点和业务落库。位点已经越过目标消息但业务记录不存在,通常指向提前提交、非原子副作用或错误过滤,不能仅凭消费日志下结论。
五、Trace 如何跨异步边界
生产时把 trace context 写入受控 header,消费时创建新 span 并 link 到 producer span。消息可能等待数小时或被多个组消费,强行维持单一父子树会扭曲持续时间;link 更能表达因果与一对多关系。
重放应创建新 replay trace,同时保留 original eventId/traceId 关联,避免与原始执行混淆。
来自外部生产者的 trace header 不能无条件信任,应校验格式、限制 baggage 大小并过滤敏感字段,防止污染采集系统或传播隐私数据。
六、成本、采样与安全
每日 10 亿条消息若每阶段都写多条日志,成本巨大。可保留生产/最终结果主索引,成功过程采样,失败、超时、死信与高价值 Topic 全量;设置分层保留期和查询权限。
禁止用 userId、订单号原文做高基数指标标签;使用哈希、exemplar 或受控查询。轨迹数据本身也要脱敏、加密和审计访问。
七、常见误区与追问
- 误区:发送日志存在就证明消息已持久化。 还要看 Broker ACK 边界。
- 误区:轨迹为空就证明消息丢失。 可能是采样或采集链路故障。
- 误区:把完整 payload 记录下来最方便。 会带来隐私和存储风险。
- 误区:异步消费必须沿用一个长父 span。 多组与长等待更适合 span link。
- 追问:如何判断慢在哪? 拆生产、排队、处理三段延迟。
- 追问:如何定位重复来源? 比较同 eventId 的生产次数与消费 attempts。
- 追问:轨迹能替代对账吗? 不能,最终业务状态仍需数据库或账本验证。
八、加强记忆
消息轨迹以 eventId 为轴,把生产、Broker、消费尝试和业务结果串起来,再用 traceId 关联原请求。它擅长定位阶段、延迟和重复来源,但可能被采样且不代表最终事实;设计时同时守住字段完整、成本、高基数与隐私边界。