如何用Jaeger 5步跑通分布式追踪:从零到生产部署的完整路径
【免费下载链接】jaegerCNCF Jaeger, a Distributed Tracing Platform项目地址: https://gitcode.com/GitHub_Trending/ja/jaeger
用户在群里投诉"下单变慢了",你翻了三小时各服务日志,只看到一堆"上游超时"的半句话。直到你在 Jaeger——CNCF 毕业的分布式追踪平台——里打开那条跨了 7 个服务的调用链:9 秒的总耗时里,有 8.2 秒卡在一句没走索引的 SQL 上。这就是链路追踪和日志的本质区别:日志告诉你"谁报了错",追踪告诉你"时间到底花在哪"。
Jaeger到底是什么 / 解决什么问题
可以把 Jaeger 理解成快递的物流跟踪系统:一个请求在微服务之间流转时,每一站的时间戳和状态都被记录成span,串起来就是一条trace(调用链)。它由 Uber 开发并捐赠给 CNCF,现在基于 OpenTelemetry Collector 构建,原生接收OTLP 协议(gRPC 4317 / HTTP 4318)。
和传统日志方案比:
| 对比项 | 分散日志 | Jaeger 分布式追踪 |
|---|---|---|
| 定位"慢在哪" | 逐服务 grep 后人工拼时间线 | 瀑布图直接看每个 span 耗时 |
| 跨服务关联 | 依赖 traceId 手工串联 | 自动聚合为一条完整链路 |
| 服务依赖关系 | 看不出来 | 依赖图直接展示 |
核心能力:
- 调用链查询与瀑布图:按服务、操作、标签、时间窗过滤,逐 span 查看耗时
- 服务性能监控(SPM):从 trace 数据直接算出 RED 指标(请求率、错误率、延迟分位数)
- 多种存储后端:memory、Badger、Elasticsearch、OpenSearch、Cassandra、ClickHouse
- 灵活采样策略:概率采样、自适应采样、尾部采样,控制高流量下的数据量
从零跑起来:最小可用环境
准备:一台装了 Docker 的机器就够了
确认端口空闲:16686(UI 和查询 API)、4317(OTLP gRPC)、4318(OTLP HTTP)。
启动:一键拉起 Jaeger All-in-one
一条命令启动包含 UI、Collector、Query、内存存储的 all-in-one 容器:
docker run --rm --name jaeger \ -p 16686:16686 \ -p 4317:4317 \ -p 4318:4318 \ jaegertracing/jaeger:latest接入应用:OTLP 是唯一的入口
v2 版本统一走 OTLP。以 Go 应用为例,最小接入代码:
exporter, _ := otlptracegrpc.New(ctx, otlptracegrpc.WithEndpoint("localhost:4317"), otlptracegrpc.WithInsecure(), // 本地开发用明文,生产记得换 TLS ) otel.SetTracerProvider(sdktrace.NewTracerProvider( sdktrace.WithBatcher(exporter), // 批量导出,减少网络往返 ))Java、Python、Node.js 用各自的 OpenTelemetry SDK,配置方式相同:把 exporter endpoint 指向localhost:4317(gRPC)或4318(HTTP)。
不想改业务代码?用官方自带的 tracegen 生成模拟流量(--network host让它访问宿主机的 4318 端口):
docker run --rm --network host \ -e OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="http://localhost:4318/v1/traces" \ jaegertracing/jaeger-tracegen:latest \ -trace-exporter otlp-http -traces 100验证:先确认数据进来了,再看界面
# 返回的服务列表里应该出现 "tracegen",说明数据已入库 curl -s http://localhost:16686/services出现结果即代表整条链路跑通了。浏览器打开http://localhost:16686进入 UI。
想要带指标监控的完整演示环境(microsim 微服务模拟器 + OTel Collector + Prometheus + Grafana),可以直接用仓库里现成的 docker-compose/monitor/:
cd docker-compose/monitor docker compose up(架构图见下图,数据流:应用 SDK → Collector → Jaeger → 存储,UI 同时查 trace 和指标)
Jaeger 监控环境架构:OTel SDK 发出的 trace 经 Collector 分流,trace 进 Jaeger 存储,聚合出的 RED 指标进 Prometheus,最终统一在 UI 呈现
看懂你的第一条追踪数据
打开http://localhost:16686,默认进入查询页。页面分三块:顶部是搜索表单(service、operation、tags、时间窗、是否只看错误),中间是 trace 列表(每条显示总耗时、span 数、服务名、时间),点进单条后是瀑布图详情。
Jaeger UI 的 trace 查询界面:上方按服务/操作/标签/时间筛选,列表区展示每条 trace 的总时长与 span 数量,点击某条进入瀑布图
以图中tracegen服务为例,几个关键读法:
- 总时长(Duration):这条链路从第一个 span 开始到最后一个 span 结束的墙钟时间,比单个 span 耗时更接近用户真实感受
- 单个 span 的耗时占比:瀑布图里最长的色块就是"关键路径"。如果 9 秒的 trace 里某 span 占了 8 秒,排查就从它开始
- operation 名:span 的操作名(如
Get、POST /api/checkout),同名 operation 的延迟突变往往就是回归点 - 错误标记:带 ✕ 的 span 表示状态码为错误,搜索表单里可以勾选只看错误 trace
核心能力详解
日常监控看什么:Monitor 标签页的 RED 三件套
v2 内置 SPM(Service Performance Monitoring)功能:jaeger-query 直接从 trace 数据算出调用率(call rate)、错误率(error rate)、延迟分位数(P50/P95/P99),在 UI 的 Monitor 标签页以曲线展示。
Monitor 标签页展示的 RED 指标:请求率、错误率和 P95 延迟按时间分布,可按服务/操作下钻
三个数字高了分别说明什么:
- P95 延迟上升:大部分请求还正常,但尾部变慢了——通常是某个下游变慢或 GC 抖动,去瀑布图里找变长的 span
- 错误率上升:配合"只看错误 trace"过滤,定位是哪个 operation 开始报错
- 请求率与延迟同步跳变:大概率是流量峰值打爆了容量,进入容量规划场景
指标也可以通过 API 直接取,方便接入自己的脚本:
# 查询 tracegen 服务最近 1 小时的 P95 延迟 curl -s "http://localhost:16686/api/metrics/latencies?service=tracegen&quantile=0.95"排障时查什么:多维过滤 + 依赖图
排障的标准动作是"缩小范围":先按service + 时间窗圈定,再加operation和tag(如http.status_code=500)收敛,最后打开具体 trace 看瀑布图。UI 的 Services 页还能看到依赖图,直观回答"谁在调我、我调了谁"。
容量规划看什么:采样策略与存储选型
高流量下全量记录既不现实也没必要,Jaeger 提供三类采样:
| 方案 | 适合场景 | 注意事项 |
|---|---|---|
| 概率采样(probabilistic) | 开发/低流量,全量或固定比例 | 无法保证"错误 trace 一条不漏" |
| 自适应采样(adaptive) | 中流量,v2 默认方向 | 按服务/operation 动态调概率,依赖 trace 反馈 |
| 尾部采样(tail_sampling) | 高流量,只留"有用"的 trace | 需等待决策窗口(如 5s),占内存 |
SPM 指标的存储也有两种路线(完整演示见 docker-compose/monitor/ 下的多个 compose 文件):
| 方案 | 适合场景 | 注意事项 |
|---|---|---|
| Prometheus 后端 | 已有 Prometheus 生态、要接告警 | 多一个组件,指标有约 60s 聚合延迟 |
| 直接查 trace 存储(ES/OS) | 已经在用 ES/OS 存 trace | 不引新组件,但查询打到 trace 库 |
| ClickHouse 同时存 trace 和指标 | 数据量大、查询并发高 | 需建表,支持create_schema: true自动建 |
生产环境怎么配才稳
推荐路径:先 all-in-one 验证 → 数据量上来后换存储、拆组件 → 接入自身监控告警。
阶段一:all-in-one + 明确数据上限
内存存储重启即丢,但开发验证够用。关键是显式设上限(参考仓库 cmd/jaeger/config.yaml):
jaeger_storage: backends: some_store: memory: max_traces: 100000 # 只保留最近 10 万条 trace,超了丢最老的,避免内存无界增长阶段二:数据量上来后换持久化存储
换成 Badger(单机)时,务必设置 TTL,否则磁盘会无限增长(参考 cmd/jaeger/config-badger.yaml):
badger: directories: keys: "/data/jaeger/" values: "/data/jaeger/" ttl: spans: 48h # 只留 48 小时,按排障习惯定;老数据靠归档而非无限保留换 Elasticsearch/OpenSearch 时,按天滚动索引方便按时间清理(完整配置见 cmd/jaeger/config-elasticsearch.yaml):
elasticsearch: server_urls: ["http://localhost:9200"] indices: index_prefix: "jaeger-main" spans: rollover_frequency: "day" # 每天一个索引,清理就是删旧索引 shards: 5 replicas: 1阶段三:把 Jaeger 自己也监控起来
v2 默认在8888端口以 Prometheus 格式暴露自身指标(见config.yaml中 telemetry 段)。至少盯这 4 个:
otelcol_receiver_accepted_spans:接收到的 span 数,突降说明上游断流otelcol_exporter_sent_spans:成功写入存储的 span 数,与接收数持续差值变大说明存储端在丢traces_span_metrics_calls_total/traces_span_metrics_errors_total:SPM 算出的调用量与错误量,可配业务告警- Jaeger 进程的内存与 CPU(容器
docker stats或 node exporter)
踩过的坑与诊断路径
数据明明发出去了,UI 里看不到
可能原因:采样策略把流量过滤掉了;endpoint 指错(4317 是 gRPC、4318 是 HTTP,混用会连不上);服务名和你搜索的不一致。
# 1. 先确认后端到底收到了哪些服务 curl -s http://localhost:16686/services # 2. 看 Collector 有没有报错(如 schema/索引问题) docker logs --tail 200 jaeger | grep -iE "error|fail"调整建议:临时把采样调成全量验证链路;确认应用端OTEL_EXPORTER_OTLP_TRACES_ENDPOINT的协议和端口匹配;搜索时用/services返回的原样服务名。
查询越来越慢
可能原因:时间窗开得太宽(默认 1h 起步,有人直接选"全部");trace 库索引膨胀没清理;单条 trace 的 span 数过多。
# ES 后端:看索引数量和大小,确认滚动索引是否生效、旧索引是否已清 curl -s 'localhost:9200/_cat/indices/jaeger*?s=store.size:desc'调整建议:养成"先窄时间窗、再放宽"的查询习惯;给旧索引设保留策略;热点查询加 service + operation 条件而不是裸查。
内存 / 磁盘持续增长
可能原因:all-in-one 内存存储接近max_traces上限;Badger/ES 没设 TTL 或滚动;队列积压(消费速度 < 接收速度)。
# 看容器内存水位 docker stats --no-stream # 对比收发差值:sent 明显低于 accepted 说明存储端写入跟不上 curl -s http://localhost:8888/metrics | grep -E "otelcol_(receiver_accepted|exporter_sent)_spans"调整建议:给 memory 后端设小一点max_traces;给持久化后端设ttl/ 索引保留天数;用tail_sampling或降低概率采样率把入口流量砍下来。
从Demo到生产:进阶玩法
如果你需要"只留慢的和错的,其他全丢":上尾部采样。在 pipeline 里挂tail_samplingprocessor,按属性或延迟过滤(仓库里有现成示例cmd/jaeger/config-tail-sampling-service-name-policy.yaml):
processors: tail_sampling: decision_wait: 5s # 等 5 秒攒齐一条 trace 再决策 policies: - name: keep-tracegen type: string_attribute string_attribute: { key: service.name, values: [tracegen-00] }如果你需要按业务维度下钻:在应用里给 span 加自定义属性(如business.tier=premium),UI 搜索表单的 tags 里就能直接按business.tier=premium过滤——这是把追踪从"技术视角"扩展到"业务视角"的关键一步。
如果你需要回答"这次发布动了哪些依赖":对比发布前后的 Services 依赖图和 Monitor 页 RED 曲线,比翻变更日志快得多。
收尾:你的行动清单
docker run拉起 all-in-one,curl http://localhost:16686/services返回tracegen- 用 OTLP 把一个真实应用接进来(gRPC 4317 或 HTTP 4318),在 UI 看到第一条自己的 trace
- 按流量规模选定采样策略:概率 / 自适应 / 尾部采样,写进配置
- 存储从 memory 换到 Badger 或 ES/ClickHouse,并显式设置 TTL / 索引保留
- 把
8888端口的自身指标接入 Prometheus,至少对 span 接收/写出差值配一条告警
从 Demo 到生产不是一次切换,而是"数据量倒逼"的渐进过程:先保证链路可见,再谈留存和告警。
核心关键词:Jaeger分布式追踪, 分布式追踪平台, 微服务性能监控, OpenTelemetry OTLP接入, Jaeger生产部署 长尾关键词:Jaeger all-in-one一键启动, Jaeger采样策略配置, Jaeger存储后端选择, Jaeger SPM服务性能监控, Jaeger故障诊断排查指南
【免费下载链接】jaegerCNCF Jaeger, a Distributed Tracing Platform项目地址: https://gitcode.com/GitHub_Trending/ja/jaeger
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考