由客户端时钟而非网关标记时间戳的链路追踪时间线
你打开了一个运行缓慢的对话追踪。模型调用竟然在用户点击发送前的 800 毫秒就开始了。你责怪了用户的笔记本电脑,关闭了标签页,继续处理其他事情。
这不仅仅是一个用户的时钟出了问题。这涉及大约三分之一的流量,而且每一个跨越客户端边界的调试会话都在读取一个根本不存在的时间线。浏览器时钟是用户可设置的,经常不同步,偶尔甚至会偏差好几天。大多数可观测性技术栈附带的检测 SDK 会使用设备报告的任何时间来标记客户端 span,通过 traceparent ID 将它们与同步服务器时钟标记的服务器 span 链接成一棵树,然后将结果交给你的值班工程师,就好像这两半具有可比性一样。它们并不具有可比性。
这里的 bug 并不是说某些时钟会漂移。Bug 在于分布式系统的基本原理——时钟会撒谎、排序需要显式同步、权威时间源是你控制的那个——在被引入 AI 可观测性技术栈时,却没有带上相应的警示。单进程追踪教会了一代工程师像对待绝对真理一样阅读火焰图。当 span 来自同一个进程时,这确实是真理 。但当第一个 span 源自不受控的浏览器时,火焰图就变成了一个包装成事实的假设。
这种失败模式是继承的,而非发明的
对话式 AI 系统跨越的信任边界比追踪模式最初设计的系统要多。一个典型的用户回合通常涉及浏览器、边缘工作节点或 CDN、API 网关、模型提供商、向量存储、几个内部工具以及数据库。每一个都属于不同的管理域。浏览器的时钟归用户所有。提供商的时钟归提供商所有。你的网关是这条路径中你唯一可以权威信任的时钟。
标准的检测模式会在每一层发出一个带有 start_time 和 end_time 的 span,取自该层恰好拥有的任何时钟。浏览器中的 OpenTelemetry JavaScript SDK 使用 performance.now() 作为单调时间源来计算持续时间,但将其锚定到 Date.now() 以获取墙上时钟时间戳,这意味着该锚点与用户的系统时钟一样错误。设备休眠一夜后,锚点不会刷新,时间戳继续漂移;SDK 仓库中有一个长期存在的问题记录,记录了出现在数小时或数天前的 span。
大多数后端提供的后期修复——重新调整子 span 到父 span 窗口内的时钟偏移调整——被 Jaeger 维护者自己称为“被认为是有害的”。调整器假设父 span 和子 span 具有相似的持续时间,这对于紧凑的 RPC 是成立的,但对于 LLM 生成几乎从未成立。它通过悄悄改写时间戳隐藏了潜在问题。它依赖于未记录的主机标识标签,并在标签缺失时退而补偿几乎所有的 span。值班工程师在阅读清理后的追踪时,已经丢失了时钟最初出错的信号。
对话式追踪让问题变得更糟
LLM 工作负载的三个特点使得这种失败模式比传统的请求-响应追踪更严重。
Span 足够长,使得偏移变得至关重要。 一个正常的 RPC 追踪由亚毫秒级的网络跳转主导,其中 50 毫秒的客户端时钟漂移只是舍入误差。一个智能体回合则由多秒钟的 LLM 调用主导,随后是每个以百毫秒计的工具调用。在 4 秒的模型调用中,客户端标记的“用户点击发送” span 中 50 毫秒的漂移是看不见的,但当你试图在相同粒度下推论首标记(time-to-first-token)延迟时,它就变成了一个调试泥潭。
因果关系很难仅从结构中读取。 在同步 RPC 树中,父子关系由调用图强制执行:父节点必须在子节点之前开始,子节点必须在父节点之前结束。智能体追踪经常违反这一点。一个与模型生成并行启动的投机性工具调用与用户 span 没有清晰的父子关系。对话中的第二个助手回复是上一个回合的子节点,但在追踪中却是它的兄弟节点。时钟偏移调整算法所依赖的结构性支撑并不存在。
- https://github.com/open-telemetry/oteps/issues/154
- https://github.com/open-telemetry/opentelemetry-js/issues/1728
- https://github.com/open-telemetry/opentelemetry-js/issues/3279
- https://github.com/open-telemetry/opentelemetry-js/issues/2705
- https://github.com/jaegertracing/jaeger/issues/1459
- https://www.jaegertracing.io/docs/2.15/deployment/configuration/
- https://www.oreilly.com/library/view/mastering-distributed-tracing/9781788628464/ch03s07.html
- https://opentelemetry.io/docs/concepts/signals/traces/
- https://opentelemetry.io/docs/languages/js/getting-started/browser/
- https://en.wikipedia.org/wiki/Real_user_monitoring
