news 2026/10/17 12:26:20

Jaeger 2.0迁移实践:拥抱OpenTelemetry,重构配置与存储

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Jaeger 2.0迁移实践:拥抱OpenTelemetry,重构配置与存储

把团队内部的分布式追踪系统从 1.x 迁到 Jaeger 2.0,前后花了一周左右。真正动手之前,我以为这只是一次常规的大版本升级,最多改改部署参数、换换镜像版本。跑起来之后才发现,从部署形态、配置方式到数据协议,2.0 几乎把整个项目的底座换了一遍。这篇文章不打算复述官方文档,而是把我实际升级过程中看到的、查到的、踩过的东西整理出来。如果你正在评估 Jaeger 2.0,或者已经走在迁移路上,希望这些内容能帮你少走几步弯路。

先说结论:Jaeger 2.0 最大的变化不是界面变好看了,也不是新增了几个查询功能,而是整个项目终于承认了一个现实——采集端应该交给 OpenTelemetry 生态,自己专注做好存储、查询和展示这一层。这个定位调整,比任何新特性都影响深远。

1. 分布式追踪生态变天,Jaeger 2.0顺势完成定位切换

1.1 为什么一个版本迭代酝酿了这么久

Jaeger 最初是从大型互联网公司内部的链路追踪系统演化而来的,开源之后很快成为云原生领域最常见的追踪后端之一。1.x 时代的功能其实已经很完善:多语言 SDK、agent 本地聚合、collector 异步处理、多种存储后端、丰富的查询 API,都是在这个阶段沉淀下来的。

但生态变化的速度比功能迭代更快。OpenTelemetry 出现之后,整个行业对"埋点、采集、传输"这件事逐步形成了统一标准。以前每个可观测性项目都有自己的 SDK、自己的协议、自己的传输格式,用户选了一个追踪系统,基本就被绑死了。OpenTelemetry 的野心是把这个局面打破:SDK 只负责采集和上下文传播,协议统一走 OTLP,后端的存储和展示可以自由选择。

在这种背景下,Jaeger 如果继续把 SDK、agent、collector 到 storage 的整套体系攥在自己手里,就会越来越孤立。1.x 的老架构设计得再精巧,也架不住"标准已经变了"这个现实。所以 2.0 的开发周期很长,本质上不是因为功能有多难写,而是需要把过去十年积累的很多设计决策推翻重来。

1.2 2.0向生态让渡了哪些能力,又守住了哪些核心

我自己的理解是,Jaeger 2.0 做了三个非常明确的取舍。

第一,采集端彻底让渡给 OpenTelemetry。曾经自家的 jaeger-client SDK 虽然还能用,但已经不在演进主线上了。agent 组件被移除,取而代之的是 OTel Collector。数据上报协议也全面转向 OTLP,Jaeger 本身不再维护一套私有的端到端协议栈。

第二,配置体系重构。1.x 里面几十个甚至上百个命令行参数,加配置文件混合使用的模式被彻底推翻,改为声明式 YAML 配置。这个变化表面上只是运维方式不同,实际上意味着 Jaeger 开始用"描述期望状态"的方式来管理自身,而不是让用户去记一堆启动参数。

第三,存储和查询能力被保留并强化。这是 Jaeger 真正的护城河。无论数据从哪里来,只要是符合 OTLP 标准或者 Jaeger 模型的 trace,你都可以往里塞,然后在 UI 和 API 上做检索、分析、对比。官方支持的存储后端也更多元,不再默认只有 Elasticsearch 一种答案。

守住核心,让渡边缘,这就是 2.0 的底层逻辑。搞清楚这一点,后面看任何具体变化都不会觉得乱。

2. 组件更精简:agent退场,UI独立,all-in-one继续保留

2.1 1.x时代的经典组件拓扑回顾

先简单回顾一下 1.x 的经典部署形态。标准链路是:SDK → jaeger-agent → collector → 存储 → query → UI。

jaeger-agent 在 1.x 里占据很重要的位置。它通常以 DaemonSet 方式部署在每个节点上,业务 SDK 通过 UDP 或 HTTP 把 span 发给本机 agent,agent 做一定的聚合和重试,再转发给 collector。这样设计的好处是,业务实例不需要知道 collector 在哪,SDK 和 collector 之间的连接数也被限制在了节点级别,网络开销更可控。

但这个设计放在今天看,问题也很明显。agent 本身是一个需要独立运维的组件,版本要升级,配置要管理,出了故障还会影响采集链路的稳定性。更关键的是,OpenTelemetry 生态已经提供了 OTel Collector 这个更强大的替代品,它不仅能接收 trace,还能处理 metrics、logs,支持各种 filter、transform、batch 插件。完全没有必要让 Jaeger 再维护一个功能重叠的 agent。

2.2 2.0部署模型里的三个明显变化

2.0 部署模型最明显的变化有三个。

第一个是 agent 组件消失。官方不再提供 jaeger-agent 镜像,也没有对应的 DaemonSet 部署方案。原来 agent 承担的职责,包括接收 SDK 数据、批处理、重试、队列等,直接由 OTel Collector 接管。你的业务 SDK 只需要把 trace 发到 OTel Collector,剩下的交给它处理。

第二个是 UI 从 query 服务里独立出来。1.x 时代 query 服务既提供 JSON API,又托管 UI 静态文件,浏览器打开一个 16686 端口就能看到控制台。2.0 里 UI 单独成为一个可部署的组件,query 服务专注提供 API。你可以选择把编译好的 UI 静态文件让 query 服务挂载,也可以把 UI 部署成完全独立的站点,甚至接入自己的鉴权体系之后再反代过去。灵活性更高,但也意味着运维拓扑多了一个节点。

第三个变化是 all-in-one 模式仍然保留。一条命令启动 collector、query、UI 和内存存储,适合本地调试、功能验证、快速截图。生产环境当然不建议这么干,但做 PoC 的时候确实方便。

1.x 组件2.0 状态替代方案
jaeger-agent移除OTel Collector
jaeger-collector保留,原生接收 OTLP直接作为 OTel 后端
jaeger-query保留,聚焦 API独立部署
jaeger-ui独立成服务可单独部署,或由 query 托管静态文件
all-in-one保留本地演示和测试

2.3 对运维链路最直接的几个影响

组件精简之后,对运维最直接的影响有两个。

一个是网络链路变短了。以前是 SDK → agent → collector,现在是 SDK → OTel Collector → collector,路径上没有本质变化,但少维护一个 Jaeger 自己的 agent 版本。如果你以前就被 agent 的升级节奏和配置问题折磨过,这个变化体会会非常深。

另一个是端口和入口的语义变了。2.0 collector 默认监听 4317 和 4318,分别是 OTLP/gRPC 和 OTLP/HTTP 的端口。如果你以前习惯把 SDK 指向 agent 的 6831 或者 5778,现在需要改成指向 OTel Collector 或直接指向 collector 的 OTLP 端口。升级期间最容易出的问题就是端口配置没改过来,数据根本没进到新链路。

3. 配置方式翻篇:命令行参数退位,声明式conf.yaml上位

3.1 旧版配置体系的问题:flag太多,根因难查

用过 1.x 的人应该都有印象,它的配置体系是"命令行参数为主,配置文件为辅"。启动一个 collector,光端口就有 gRPC、HTTP、管理端口,还有存储类型、存储地址、队列大小、采样策略路径…… 如果不封装一层 Helm values,用户就要在 systemd unit 或者 docker run 命令里塞几十个--xxx.yyy参数。

这种设计在单体时代还能忍,但到了 Kubernetes 环境就很痛苦。配置散落在各种 Values 文件里,模板套模板,最后到底哪些参数生效、优先级怎么样,经常要跑到容器里去验证。出了问题排查链路特别长,因为根本没法快速说清楚"当前进程到底用了哪一组配置"。

3.2 v2配置文件的骨架与命名空间逻辑

2.0 把配置统一收敛到一份 YAML 文件里,靠命名空间区分组件。下面是一个最基础的 collector 配置示例:

jaeger: collector: service: host-port: "4317" http-port: "4318" storage: type: elasticsearch elasticsearch: server-urls: "http://elasticsearch:9200" query: service: host-port: "16686"

结构很清晰:jaeger.collector管采集,jaeger.storage管存储,jaeger.query管查询。每个组件关心的配置都收敛在自己对应的命名空间里,不会出现以前那种存储参数散落在不同 flag 分组里的情况。

环境变量的机制仍然保留,这样在做容器化部署时可以结合 Kubernetes Secret 使用。例如下面的写法可以在运行时覆盖存储地址:

export JAEGER_STORAGE_TYPE=elasticsearch export JAEGER_STORAGE_ELASTICSEARCH_SERVER_URLS=http://elasticsearch:9200

注意环境变量的层级要和 YAML 的嵌套结构对应,命名方式是大写下划线分隔。这里容易踩坑:环境变量优先级高,一旦设置它,YAML 里对应的配置就会被覆盖。

3.3 配置迁移阶段容易忽略的三个细节

实际迁移过程中,有三个细节特别容易忽略。

第一个,旧 flag 不会再被读取。有些团队会在启动命令里加上--collector.otlp.enabled=true这类 1.x 参数,指望新版本兼容识别,结果进程起不来或者根本没有任何 OTLP 端点监听。2.0 只认新式配置,老参数要么删除,要么逐项映射到 YAML。

第二个,UI 的配置不再是 query 配置的一部分。如果独立部署 UI,它的监听端口、api 地址都需要在 UI 自己的配置里指定,而不是挂在jaeger.query下。这个细节文档里有写,但很容易被忽略,因为大家已经习惯了"打开 query 端口就有 UI"。

第三个,远程采样配置的结构发生了调整。1.x 里通过/api/sampling接口下发采样策略,配置方式比较固定。2.0 里采样策略的配置路径和表达方式要重新确认,特别是如果你用了自定义采样规则,不要直接复制旧配置,先确认新版本还认不认这套格式。

4. 数据入口倒向OTLP,原生协议冻结之后

4.1 默认端口与原生协议:OTLP带来的直接变化

Jaeger 2.0 collector 原生接收 OTLP,这带来几个直接变化。

首先是端口问题。默认情况下 collector 监听 4317 和 4318,分别对应 OTLP/gRPC 和 OTLP/HTTP。如果你用 OpenTelemetry SDK 上报 trace,直接把 endpoint 指向这里就行,不需要额外的协议转换层。

其次是数据模型的对齐。OTLP 的 span 结构几乎原样映射到了 Jaeger 的存储模型里,attribute 对应 tag,event 对应 log。以前 Jaeger 内部有自己的一套 protobuf 定义,现在这套定义被冻结在 jaeger-idl 里,不再跟随新需求演进。也就是说,未来所有新特性都会基于 OpenTelemetry 的数据模型来增长,旧格式将停留在"兼容但不发展"的状态。

第三是语义约定(semantic conventions)的影响。以前 Jaeger 的原生 SDK 和 agent 有自己的 tag 命名习惯,比如http.url、peer.service。OTLP 生态里这些字段有统一的命名和组织方式,如果埋点 SDK 升级到了 OTel,进入 Jaeger 的 span 会携带更多标准化字段,对跨团队协作和统一查询是好事。

4.2 老SDK的兼容路径:能跑,但不要当长期方案

升级时最现实的问题是:存量服务如果还在用旧版的 jaeger-client SDK,2.0 还认不认?

官方给出的答案是提供兼容端点,主要是 jaeger.api-v1 这一层。老的 thrift 格式上报数据仍然可以被接收,所以短期内你不必把所有 SDK 全部切换完,业务服务可以先继续跑旧 SDK,数据一样能从 UI 里查到。

但我不建议把这个状态维持太久。原因有两点:第一,旧 SDK 背后的通信格式和协议已经冻结,社区不再继续在上面投入精力,出了数据丢失、采样异常这类问题,只能靠自己的经验去排查;第二,OpenTelemetry SDK 在自动埋点、上下文传播、指标和日志联动上做得越来越好,继续留在旧协议上等于放弃了这些能力。我的建议是,给一个明确的切换周期,把核心服务的 SDK 逐步换成 OTel,旧的兼容端点作为过渡手段保留,而不是长期依赖。

4.3 数据模型对齐OTel后的连带影响

字段变化还会带来连带的运维影响。

最典型的是 Elasticsearch 索引 mapping 的变化。Jaeger 存储在 ES 里的索引结构是跟随数据模型走的,2.0 的数据模型对齐 OTLP 之后,索引里的字段、类型、嵌套结构都可能有差异。你不能指望把 1.x 的索引拷贝到新集群里,然后让 2.0 query 直接查。团队如果打算保留历史数据,一定要提前做索引重建和数据迁移的评估,而不是简单复用旧索引。

另一个连带影响是查询 API 返回的 JSON 结构。虽然 v1 API 还保持着主要兼容,但字段名和层次可能微调,依赖 API 做告警或者二次开发的系统要重新跑一遍接口测试。我们团队就有一个基于 trace API 做的内部诊断工具,升级后字段路径变了,不得不跟着改了一版。

5. 存储后端不再默认ES:多存储选型的现实考量

5.1 当前存储后端支持情况一览

Jaeger 历来在存储层给了很多选择,但不同后端的成熟度差异很大。2.0 时代的支持情况可以大致列成下面这个表:

后端支持级别部署复杂度适合规模一句话评价
Elasticsearch / OpenSearch官方中高中大型生态成熟,查询灵活,运维负担重
Cassandra官方高超大规模写入扩展性好,运维门槛偏高
Badger官方(实验)低单机适合本地和边缘场景
内存存储官方极低演示测试数据不持久,重启即丢
ClickHouse社区中大规模 + 分析压缩率高聚合快,但配套不够完善

5.2 ClickHouse:看起来很香,落地前要掂量

ClickHouse 在可观测性领域一直是热门话题,它的列式存储特性天然适合 trace 数据这种高吞吐、低更新、分析型查询的场景。压缩率高,存储成本能省不少;聚合查询快,按服务、按接口统计耗时占比很顺手。

但我建议你在引入之前认真掂量几件事。

第一,社区方案往往不是官方维护,版本兼容性要自己盯着。Jaeger 的版本每升级一次,ClickHouse 的存储插件是否及时跟上、是否需要改表结构,这些都要自行验证。我们团队在做选型时专门搭建了一套测试环境,模拟了三个月的数据量,跑了一轮查询演练,才确认它符合预期。

第二,ClickHouse 本身擅长的是大批量写入和分析查询,但在链路追踪场景里,UI 的一个搜索请求往往会带上复杂过滤条件,这跟 ClickHouse 擅长的场景不一定完全匹配。需要花时间调表结构、索引、分区策略,甚至要考虑是否引入物化视图来服务常见查询。

第三,运维技能栈的问题。很多团队对 ES 很熟,但对 ClickHouse 的运维经验几乎是零。选一个新存储等于同时引入一个新数据库去维护,评估成本一定要算进去。

5.3 按规模做存储选型的实操建议

结合不同规模我给一个实操建议。

本地开发和个人试验,直接用 all-in-one 带内存存储,简单直接。小规模微服务,比如十几个服务以内、每天几千万 span 的量级,一个单节点 ES 加上索引生命周期管理就够用了,不要一上来就上集群。中大型规模,建议 ES 至少三节点起步,开启索引分片和生命周期策略,给查询留足性能余量。

如果你确实需要保留很长时间的数据,并且有深度的聚合分析需求,再认真评估 Cassandra 或者 ClickHouse。每个存储都有各自的取舍,没有一个后端是通吃所有场景的。选型之前一定要拿自己的真实数据量、查询模式、保留周期跑一轮 PoC,只看宣传文章是不靠谱的。

6. 从1.x迁到2.0的实操步骤、兼容坑与验证清单

6.1 迁移之前先把这三个问题问清楚

动手迁移之前,我建议先回答三个问题。

第一,你现在依赖哪些 1.x 特有功能?比如 agent 的本地限流规则、某些自定义 tag 的解析逻辑、旧版 UI 里已经配置好的仪表盘。这些功能在 2.0 里可能不复存在,或者以完全不同的方式提供。如果团队对这些功能有强依赖,迁移成本会比预想的高很多。

第二,历史数据是否需要完整保留?如果需要,必须提前评估索引重建和数据导出导入的方案。Jaeger 2.0 的数据模型和旧 ES 索引结构不兼容,不是简单把旧索引 alias 改一下就能解决的。如果不需要保留,直接冷启动新集群,让 2.0 开始接收新数据,反而省事很多。

第三,下游系统对 Jaeger API 的依赖程度如何。告警对接、内部诊断工具、自动化的 trace 分析脚本,这些都建立在对 query API 的调用上。升级之前把相关代码的接口调用梳理一遍,能大幅降低上线后的意外。

6.2 我们采用的低风险并行迁移路径

我们实际采用的是并行迁移的策略,整体分成了三步。

第一步,先用 all-in-one 模式本地跑一个 2.0,接入几条测试服务链路,验证 SDK 上报、UI 查询、采样配置这些基础功能是否正常。这一步成本很低,半天就能做完,主要是让自己熟悉新配置和新的部署方式。

第二步,部署独立的 collector + query + 新 ES 索引集群。业务测试环境全部把 trace 发到新 collector,连续跑几天,确认数据量、查询耗时、组件稳定性都符合预期。这一步的关键是不要动生产环境,只让测试流量进入新链路。

第三步,确认无误后再切换生产入口。我们保留了旧的 1.x 集群运行了一段时间,新老数据同时存在。等所有业务都切到新链路并且稳定运行后,再关停旧集群。

这个路径的好处是每一步都有验证节点,即使出现问题,也能随时回退到旧链路。比起大版本原地升级,操作上多花了一点时间,但风险低很多。

6.3 上线前的验证清单和常见故障定位

最后分享一份我们上线前使用的验证清单,照着跑一遍基本能覆盖主要风险:

  • SDK 上报链路验证:检查 collector 日志能看到新 span 进入,UI 能查到对应 trace。
  • OTLP 端口验证:分别测试 4317 的 gRPC 和 4318 的 HTTP 两种上报方式。
  • 采样策略验证:远程采样配置下发后,确认采样率按预期生效。
  • UI 连接验证:独立部署的 UI 能否正确访问 query API,搜索、Trace 详情页是否正常。
  • 历史数据验证:如果需要导入旧数据,抽样比对查询结果是否一致。
  • 下游 API 验证:告警和内部工具调用 query API 的链路是否全部通过。

还有一个常见故障值得单独说:如果你在升级后发现新集群启动正常,但 UI 里一直没有新数据,先别急着查网络,直接看 collector 是不是真的在使用你配置的存储。我们当时漏掉了一个自定义存储参数的映射,导致 collector 启动后默认往内存存储里写数据,进程一重启全部清空。这种问题日志里不一定会报错,最有效的排查方式是先插入一条测试数据,然后去存储后端里确认数据是否真的落盘了。

这次升级走完,我最大的体会是:2.0 的变化不是新功能堆叠,而是把 Jaeger 放回了它该在的位置。采集交给 OpenTelemetry 生态,自己专注存储、查询和 UI。对使用者来说,这意味着部署链路更干净,也更符合可观测性领域当下的主流标准。如果你正准备升级,建议先按上面这份清单做一轮摸底,把依赖项、历史数据、下游调用梳理清楚再动手,别看到一个新版本就直接切。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 12:24:42

Superpowers开发者工具链:可审计、可嵌入的AI能力协议

1. “Superpowers”不是超能力,而是开发者工具链的隐喻性命名体系 最近在多个技术社区和开发工具文档里反复看到“Superpowers”这个词——它既不是漫威电影里的设定,也不是某个新出的AI模型代号,而是一套正在快速演进的 开发者增强型工具命…

作者头像 李华
网站建设 2026/10/17 12:24:42

ONVIF Java SDK实战:设备发现、RTSP取流与PTZ控制全解析

简介:这份 ONVIF JAVA SDK 面向从事网络摄像头接入、视频监控平台开发及物联网设备集成的 Java 工程师,帮助开发者快速理解并实现 ONVIF 协议的核心交互流程。资源包共 1157 个文件,以 1147 个 Java 源码为主体,辅以 5 个 jar 依赖…

作者头像 李华
网站建设 2026/10/17 12:23:17

马肯依码士9410-9450串口协议实操指南:握手-加载-执行三段式通信

简介:本资源是面向工业自动化与嵌入式开发工程师的马肯依码士(Markem-Imaje)9410–9450系列喷码机串口通讯实战方案,聚焦设备协议解析与上位机控制开发。资源完整提供英文版官方通讯协议PDF、中文使用说明RTF文档,以及…

作者头像 李华
网站建设 2026/10/17 12:23:14

74HC165驱动实战:STM32低成本扩展16路数字输入

简介:本资源是一份面向STM32嵌入式开发者的74HC165并行输入/串行输出移位寄存器驱动实现,专为解决I/O资源受限场景下的多路外部信号采集问题,适用于矩阵键盘扫描、多通道开关检测、简易数据扩展等典型应用。压缩包仅2个文件(1KB&a…

作者头像 李华
网站建设 2026/10/17 12:22:28

Ubuntu安装显卡驱动后进不去桌面?命令行排查与修复指南

1. 从图形界面掉进命令行:先搞清楚到底发生了什么Ubuntu 开机之后没进桌面,屏幕上只剩一行行白字黑底的命令行,登录进去之后startx也起不来,或者干脆连startx都没装。这种情况我遇到过太多次,绝大多数都发生在装完显卡…

作者头像 李华