LinkedIn 如何用 OpenTelemetry 实现分布式追踪

LinkedIn 用 OpenTelemetry 把移动端、网页端与后端请求串成一条链路。小编解读 pageForestId、Kafka 与 ClickHouse 存储、协调式头部采样等做法。

用户在手机上点一下失败了,问题到底出在客户端还是后端?小编先给结论:LinkedIn 用 OpenTelemetry 把移动端、网页端的用户操作,和处理这些请求的后端服务串成了一条完整链路,工程师可以沿着单次交互穿过多个服务,找出失败发生的位置。据 LinkedIn 的工程博客,公司重建了遥测基础设施,来弥补客户端分析与后端监控之间的空白;此前调查一次失败的交互,工程师往往得手动拼接来自不同监控系统的信息。

新架构在 iOS、Android、网页应用和后端服务里统一使用 OpenTelemetry 来标准化追踪数据,并把源自同一次用户交互的请求关联起来,让工程师能把客户端故障和涉及的后端操作放在一起调查。

把前端和后端的追踪连起来

LinkedIn 的分布式架构会把用户请求分发给多个服务。比如打开一个页面,可能分别触发获取信息流内容、个人资料信息和通知数量的请求。公司引入了名为 pageForestId 的标识符,把这些请求放在同一个页面上下文里:每个服务器请求仍保留自己的 OpenTelemetry traceId,额外的标识符则把相关追踪分成一组,直到用户离开该页面。

客户端发送请求时,LinkedIn 的前端会从不同的请求头里,分别提取客户端的追踪信息和 pageForestId,然后为服务器请求新建一条 OpenTelemetry 追踪,并把它的根跨度链接到发起请求的客户端跨度。这样每个后端请求都能沿着处理它的各个服务被追踪,pageForestId 则保持它与原始页面交互的联系;工程师既可以查看单个请求,也能取回与同一页面相关的多条追踪。

LinkedIn 同时对客户端应用和后端服务做了插桩。共享的 HTTP 和 gRPC 框架会自动捕获标准请求路径,需要更细监控的操作,开发者可以另外添加跨度。后端支持用 Java、Python、Go 和 Rust 编写的服务,针对各语言的封装层,保证这些环境中追踪行为的一致,包括服务之间追踪标识符的传播。

由于页面浏览并不总有可靠的结束事件,LinkedIn 还会提前关闭页面根跨度:子跨度继续引用根跨度,最新的子跨度决定实际的页面上下文时长。为了在各平台上维持一致的追踪数据,LinkedIn 还扩展了 OpenTelemetry 的语义约定,加入由内部治理的属性,用于客户端旅程和公司特有的操作。

管理遥测采集与数据量

追踪基础设施用 Apache Kafka 传输遥测数据,用 ClickHouse 存储并查询来自客户端应用和后端服务的跨度。客户端跨度会先转换成 LinkedIn 现有的跟踪格式,再进入遥测管道;服务器端跨度则直接发布到 Kafka,两路数据随后都被写入 ClickHouse。LinkedIn 复用了现有的客户端跟踪基础设施,而不是另建一套传输系统:兼容层把完成的 OpenTelemetry 跨度转换成公司既有的跟踪模式,让它们走现成的投递管道。

每个跨度都按 pageForestId、traceId 和时间戳建立索引,工程师因此能取回某次页面交互相关的请求、查看单条追踪,并跟踪各操作发生的先后顺序。系统提供两种视图:

视图显示内容
客户端级视图一次页面会话中的活动,及其相关的服务器请求
服务器详情视图涉及的后端服务,包括执行时间和错误

采集这些信息,也意味着 LinkedIn 得管理应用和服务产生多少遥测数据。公司使用协调式头部采样:在操作开始时就做出采集决定,依据一项使用了假名化成员标识符的策略,让相关活动保持一致。LinkedIn 工程博客的作者 Aashay Mittal 及其合著者写道,客户端和服务器各自孤立的决定,可能产生部分追踪,价值很小,甚至支持错误结论。因此 LinkedIn 在整个基础设施里传播采样决定,而不是让客户端和服务器系统各自独立选择追踪;同时对员工请求用更高的采样率,以便内部测试时有更多完整的追踪。

LinkedIn 还把用于体验质量(QoE)监控的遥测,与优先级较低的调试数据分开:客户端跨度带有标记,说明它是否计入 QoE 指标,这样非必要的跨度就能以较低的比例采样。据 LinkedIn 称,在正常运行条件下,大约 30% 的客户端跨度被归为对 QoE 指标非关键;这个比例会随着工程团队添加更多调试跨度而变化,而性能监控和告警所需的遥测,则不会被这些削减波及。

后端可削减的空间更大,因为入口跨度只占追踪活动里相对较小的份额,大多数后端跨度涵盖的是内部操作和外发调用,LinkedIn 表示可以把它们当作较低优先级的调试数据。公司估计,这种做法给出的余地,最多能削减约 90% 的后端追踪量,但这个数字只是对潜在削减幅度的估计,并不是实测的存储或运营成本下降。

移动端遥测采集还有另一个挑战:操作系统可能在跨度导出之前,就挂起或终止应用。LinkedIn 用自定义的批处理器管理导出间隔、队列大小和负载上限,包括把过大的追踪拆成较小的事件。某些与生命周期相关的跨度会立即导出,追踪器还会在应用进入后台时,尝试清空待发送的数据。LinkedIn 承认,应用被突然终止时,仍可能造成遥测丢失。

为了监控追踪本身占用的资源,LinkedIn 用性能分析钩子和开发者浮层来衡量插桩开销;公司还采用属性过滤、脱敏和访问控制,降低收集或暴露个人信息的风险,追踪数据大约保留一周。

追踪生产环境的故障

LinkedIn 记录了两起涉及 iOS 应用的生产排查,演示工程师如何用这套追踪系统调查故障:

  1. 请求超时:工程师把一次失败的客户端操作,追踪到一个超出期限的下游后端请求。链路追踪直接指出了受影响的服务操作,无需手动关联分散的客户端与服务器监控记录。
  2. 无障碍校验错误:信息流组件中出现无障碍校验错误,校验系统在界面定义里检测到缺失的无障碍标签,关联的追踪则把工程师引向相关的服务端数据解析步骤和涉及的组件。工程师在多个样本里确认了同一个错误,再推出修复。LinkedIn 说明,配套的图示使用的是示例数据,而不是真实的生产追踪。

想了解更多 OpenTelemetry 实践,可以接着读小编的另外两篇:Grafana 插桩中心正式可用:自动注入 OpenTelemetry SDK,以及 Anthropic 接入 Databricks MLflow,Claude 追踪数据原生导出。

(题图来自 Unsplash 摄影师 Zulfugar Karimov)

常见问题(FAQ)

pageForestId 是做什么用的?

它把同一个页面上下文里的多个请求分成一组,每个请求仍有自己的 traceId,直到用户离开该页面。

LinkedIn 用什么存储和传输追踪数据?

用 Apache Kafka 传输,用 ClickHouse 存储和查询跨度,数据保留约一周。

为什么要用协调式头部采样?

客户端和服务器各自独立决定采样,会产生残缺的追踪,价值很小,甚至支持错误结论,因此要在整个基础设施里传播同一个采样决定。

“削减 90% 的后端追踪量”是实测结果吗?

不是。LinkedIn 说明这只是对潜在削减幅度的估计,并非实测的存储或运营成本下降。