你从电商平台下单后,最关心的就是“包裹到哪了”。快递公司为此准备了一套缜密的全链路物流追踪:每个中转站都要扫码,记录“已到达华东分拨中心”“已离开华东分拨中心”;所有记录挂在一个唯一的物流单号下,客服输入单号就能看到包裹的完整旅程。现在想象你的微服务系统:一次点击“结算”的请求,会像一件包裹一样,依次穿过网关、订单、支付、库存等服务。某一环慢了一拍,用户就会感到页面卡顿。问题来了——你如何知道包裹卡在了哪个中转站?这就是 Jaeger 存在的意义。它给每个请求发放一张“物流单号”(Trace ID),为每个被调用的服务生成一条“扫描记录”(Span),最后在界面上还原出整条运输路线图(Trace)。本文带你从零认识 Jaeger:追踪的核心概念、部署架构、与 Kubernetes 的集成方式、采样策略、监控告警联动,以及如何用它定位性能瓶颈,把“系统好像慢了”变成“支付服务第三号实例慢了 800 毫秒”。

岗位关联

对 DevOps 工程师而言,Jaeger 是把“告警触发”与“根因定位”之间的鸿沟填平的关键工具。掌握它,你就从“系统又出事了”的被动救火者,升级为“链路一眼看清”的主动管控者,这是现代运维体系中的核心加分技能。

目录
  1. 可视化演示
  2. 1. 追踪基础概念
  3. 2. 部署架构组件
  4. 3. Kubernetes集成
  5. 4. 采样策略配置
  6. 5. 监控告警联动
  7. 6. 性能分析调优
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

分步演示Jaeger四组件架构流水线、Trace瀑布图关键路径分析、以及四种采样策略的覆盖率与性能开销对比。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Jaeger四组件架构 App产生Span→Agent本地聚合→Collector处理 Collector为中心节点负责校验存储路由 Span:{traceID,spanID,parentID,op,tags} Jaeger架构源自Google Dapper论文的四个核心组件

1. 追踪基础概念

你从电商平台下单,包裹发出后每经过一个中转站都会被扫码——“已到达华东分拨中心”“已离开华东分拨中心”。这些扫描记录串起来,就是包裹的完整旅程。而每次寄件,快递单上都有一个唯一的单号,客服输入单号就能调出全部转运记录。微服务世界里发生的事情,和这套“快递全链路追踪”几乎一一对应:一次用户请求就是一件包裹,每个被调用的服务就是沿途的中转站。

一次典型的“点击结算”请求,会依次经过网关、订单、支付、库存等服务。如果其中支付服务响应了 2 秒,其他环节都只要 50 毫秒,整体体验依旧很卡。问题是:你怎么知道卡在支付?分布式追踪系统把一次完整请求定义为一个 Trace(追踪),把其中每一次服务调用定义为一个 Span(跨度)。同一个 Trace 的所有 Span 共享同一个 Trace ID——这就像同一个包裹的所有中转记录共享同一个物流单号,无论包裹走到哪个分拨中心,扫码枪都能把它归到同一单下。

Span 不仅要记录“调用了谁”,还要记录开始时间、结束时间、耗时和附加标签。更重要的是,Span 之间有父子关系:订单服务调用支付服务产生的 Span,它的父节点是订单服务的 Span。把这些关系拼接起来,一次请求就变成了一棵“调用树”——根在入口网关,枝干是各服务调用,叶子是数据库、外部 API 等最终操作。

当你打开 Jaeger 界面看到那棵瀑布状的“调用树”时,其实就和打开快递详情页一样:整条运输路线(Trace)一目了然,每一段运输记录(Span)的耗时都分毫不差地摆在面前。系统不再是一个黑盒,而是一条你能“按图索骥”的透明流水线。

T={s1,s2,…,sn},s1.p=∅,si.p=si−1 (i≥2)T = \{s_1, s_2, \ldots, s_n\}, \quad s_1.p = \varnothing, \quad s_i.p = s_{i-1}\ (i \geq 2)
一个 Trace 是由 n 个 Span 组成的集合,其中 p 表示“父 Span”指针。第一个 Span 没有父节点,后续每个 Span 都指向前一个 Span,这条链就是请求的完整路径。
  1. 集合定义$T$ 表示一次完整追踪,它由 $s_1$ 到 $s_n$ 共 $n$ 个 Span 组成,对应请求穿越过的所有服务调用。
    T={s1,s2,…,sn}T = \{s_1, s_2, \ldots, s_n\}
  2. 根节点语义$s_1.p = \varnothing$ 表示第一个 Span 没有父节点,它是整棵调用树的根,通常对应网关或入口服务,也是 Trace ID 最先诞生的地方。
    s1.p=∅s_1.p = \varnothing
  3. 链式关系$s_i.p = s_{i-1}$ 表示每个后续 Span 的父指针指向前一个 Span,形成一条从入口到出口的调用链——这正是“物流单号+中转站顺序”的数学表达。
    si.p=si−1,i≥2s_i.p = s_{i-1}, \quad i \geq 2

2. 部署架构组件

快递公司要支撑全城的包裹追踪,不能只靠一个“查快递的网页”,背后是整条流水线:每个网点埋扫码枪采集数据,数据汇到分拨中心统一处理,再写入档案仓库,最后客服在官网查询界面上输入单号就能看到行程。Jaeger 的架构设计也遵循同样的“采集—汇聚—存储—查询”四层思路。

第一层是 Agent(采集端),它贴近应用运行,接收应用内 SDK 上报的 Span,再转发给下游。第二层是 Collector(收集器),负责接收所有 Agent 送来的数据,做格式校验、数据清洗、分配存储,是整条流水线的“分拨中心”。第三层是存储后端,生产环境常用 Elasticsearch、Cassandra 或本地 Badger,相当于快递公司的档案仓库,Span 数据在这里持久化。第四层是 Query 服务与 Web UI,用户通过它按 Trace ID 或服务名检索链路,相当于快递官网的查询页面。

生产环境中,Collector 和数据存储通常需要多副本部署,否则一旦“分拨中心”或“档案仓库”故障,整条追踪链路就会断档。数据流向是单向的:应用 SDK → Agent → Collector → 存储 → Query。理解这个顺序,你就知道“为什么刚发生的请求在 UI 里查不到”——数据还在路上,还没写入仓库。

就像快递详情从“已扫件”到“可在官网展示”之间总有几秒延迟一样,Jaeger 的追踪数据也有入库延迟。明白了这条流水线的结构,你部署 Jaeger 时就不会把 Agent、Collector、存储胡乱堆在一起,而是清楚每一层该承担什么职责、该备多少冗余。

Le2e=Le+Ln+Lq+LwL_{e2e} = L_e + L_n + L_q + L_w
从 Span 产生到能在 UI 查到,存在端到端滞后 $L_{e2e}$,它等于应用内发出耗时、网络传输耗时、Collector 排队耗时和写入存储耗时之和。这个滞后一般是毫秒到秒级,是分布式系统的正常现象。
  1. 端到端延迟$L_{e2e}$ 表示一条 Span 从应用发出到能在查询界面看到所经历的总时间,它决定了追踪数据的“新鲜度”。
    Le2eL_{e2e}
  2. 四个环节累加$L_e$ 是应用内序列化和发出的耗时,$L_n$ 是网络传输耗时,$L_q$ 是 Collector 缓冲队列中的等待耗时,$L_w$ 是写入存储的耗时,四者相加得到总滞后。
    Le2e=Le+Ln+Lq+LwL_{e2e} = L_e + L_n + L_q + L_w
  3. 工程意义这条公式解释了为什么追踪系统通常“延迟几秒可查”是健康状态,也告诉你在数据延迟过高时该排查哪个环节——是网络拥堵了,还是 Collector 积压了。
    Le2e→min⁡L_{e2e} \rightarrow \min

3. Kubernetes集成

快递分拨中心的自动分拣机可以随货量灵活增减:双 11 货量暴涨就临时加开几条分拣线,淡季则关停部分设备。在 Kubernetes 里部署 Jaeger 也是同样的逻辑——我们希望用声明式的方式描述“需要几条分拣线”,让集群自动完成扩缩容,而不是运维手工搬机器。

在 K8s 中部署 Jaeger,最推荐的方式是使用 Jaeger Operator。它像一个“自动分拣车间主任”:你只需要定义一个 Jaeger 类型的自定义资源(CRD),描述 Collectorg 副本数、存储类型、采样默认值等期望状态,Operator 就会负责创建 Deployment、Service、Ingress,并处理升级和故障恢复。相比手工编写一堆 YAML,Operator 让整个部署过程变成“填一张快递面单”那么简单。

应用侧的数据采集同样讲究。早期 Jaeger 会以 sidecar 方式在每个应用 Pod 里注入 Agent,但这种方式有额外资源开销;现在官方更推荐应用通过 SDK 以 OTLP 协议直接上报给 Collector,对 K8s 环境更友好。网络配置上,你需要把 Query 服务通过 Ingress 暴露给运维同学访问,同时让 Collector 的采集端口能被集群内的应用访问到。至于弹性伸缩,可以给 Collector 配置 HPA,让它依据 CPU 或处理延迟自动增减副本——这正是“按货量开分拣线”的自动化版本。

掌握了“每台分拣机每小时能处理多少件包裹”,你就能在业务高峰来临前算好需要多少 Collector 副本。Jaeger Operator 与 HPA 的组合,让“高峰期自动加开分拣线,低谷期自动收线”从理想变成日常。

Npod=⌈Qspanqpod⌉N_{pod} = \left\lceil \frac{Q_{span}}{q_{pod}} \right\rceil
Collector 的最小副本数等于每秒需要处理的 Span 总数除以单个 Pod 的处理能力,再向上取整。这是 Jaeger 在 K8s 上做容量规划的基本估算公式。
  1. 吞吐需求$Q_{span}$ 表示系统每秒产生的 Span 总量,它等于每秒请求数乘以每个请求的平均 Span 数。
    Qspan=R×nspanQ_{span} = R \times n_{span}
  2. 单副本能力$q_{pod}$ 表示一个 Collector Pod 每秒能处理的 Span 数,可以通过压测得到,它与 CPU、内存配置和网络带宽相关。
    qpodq_{pod}
  3. 向上取整$\lceil \cdot \rceil$ 表示向上取整,因为副本数必须是整数且不能低于需求,比如 3.2 个 Pod 就要部署 4 个副本。
    Npod=⌈Qspanqpod⌉N_{pod} = \left\lceil \frac{Q_{span}}{q_{pod}} \right\rceil

4. 采样策略配置

如果给每一个包裹都装上实时 GPS 定位,物流成本会高得惊人。聪明的快递公司只对贵重件、加急件做全程精细追踪,普通件只保留关键节点扫描。分布式追踪系统同样不能 100% 全量采集——每请求 20 个 Span、每秒 1000 个请求,就意味着每秒产生 2 万条记录,存储和带宽成本会迅速失控。于是“采样”成为追踪系统上线前必须回答的问题。

Jaeger 提供多种采样器。第一种是全量采集(const),要么采所有请求,要么一个不采,适合测试环境或低流量场景。第二种是概率采样(probabilistic),按固定比例抽取请求,比如 0.1 表示只追踪 10% 的请求,生产环境最常见。第三种是速率限制(rate-limiting),保证每秒钟最多采集指定数量的 Span,防止突发流量打爆 Collector。第四种是远程采样(remote),应用启动时从 Collector 动态拉取采样策略,运维可以在运行时调整采样率而无需重启应用——这是 Jaeger 最具工程价值的特性之一。

采样不是“少采一点”的无奈妥协,而是用可控的成本换取统计有效的可观测性。概率采样保证流量形态的随机代表,速率限制保护系统峰值,远程采样让策略可以灰度调整。三者组合,就能在“看得全”和“存得起”之间找到平衡点。

当业务量翻倍时,保持存储预算不变,只需把概率采样率减半——就像快递公司把 GPS 追踪从“每 10 个包裹装 1 个”调成“每 20 个装 1 个”。理解采样,你就能在成本和可观测性之间自由调节旋钮,而不是面对暴涨的账单束手无策。

C=Nr×Ns×pC = N_r \times N_s \times p
每秒需要写入存储的 Span 数量等于请求速率乘以每请求 Span 数,再乘以采样率。这个公式直接决定你的存储集群该买多大。
  1. 请求速率$N_r$ 表示每秒进入系统的请求数,也就是 QPS,它可以通过网关或负载均衡器的指标获得。
    Nr=QPSN_r = \text{QPS}
  2. 每请求 Span 数$N_s$ 表示一个请求平均会产生多少个 Span,取决于服务链长度——链路越长、分支越多,这个值越大。
    NsN_s
  3. 采样率系数$p$ 是采样率,取值范围 0 到 1。三项相乘就得到每秒实际写入存储的 Span 总量,是容量规划的核心输入。
    C=Nr×Ns×pC = N_r \times N_s \times p

5. 监控告警联动

物流公司考核每个网点的时效,通常会盯三件事:每天处理多少包裹(业务量)、有多少包裹延误或丢失(异常率)、包裹平均几小时送达(时效)。这套“量、错、时”的打法,放在微服务监控里就是经典的 RED 方法。Jaeger 能把一条调用链路看得清清楚楚,但它本身不是告警系统——就像物流详情页不会自动给你的手机发“包裹延误”短信,你需要一套独立的监控告警体系来盯数据。

RED 方法定义了三个核心指标:Rate(速率,每秒请求数)、Errors(错误数或错误率)、Duration(耗时分布,如 P50、P95)。你可以通过 Jaeger 的 spanmetrics 能力把追踪数据转换为这些指标,然后导出到 Prometheus 存储,再由 Alertmanager 依据规则触发告警。例如“订单服务 P95 延迟超过 800 毫秒持续 5 分钟”或“支付服务错误率超过 1%”,一旦触发,运维立即获得告警通知。

告警通知只是第一步,真正的闭环在于:告警消息中带上 Trace ID 或服务名,运维登录 Jaeger UI 搜索对应时段的链路,从瀑布图上直接看到底是哪个 Span 慢了、哪个 Span 报了错。这就像客服收到“包裹异常”投诉后,第一件事就是调出物流轨迹——追踪系统为告警提供了“下一跳”的定位能力。

告警是“投诉电话”,Jaeger 是“物流轨迹”,两者配合才能真正形成从发现到定位的闭环。脱离了追踪系统的告警只会告诉你“系统出事了”,而接上 Jaeger 的告警会告诉你“哪个服务、哪个环节,甚至在哪个 Pod 上出事了”。

E=NerrNtot×100%E = \frac{N_{err}}{N_{tot}} \times 100\%
错误率等于错误 Span 数除以总 Span 数再乘以 100%。它是 RED 方法中最直接反映系统健康状况的指标,也是告警规则里最常见的触发条件。
  1. 错误计数$N_{err}$ 表示在统计窗口内标记为错误的 Span 数量,比如返回 5xx 状态码或抛出异常的服务调用。
    NerrN_{err}
  2. 总量计数$N_{tot}$ 表示同一窗口内所有 Span 的总数,包含成功和失败的全部调用。
    NtotN_{tot}
  3. 百分比转换两者相除再乘以 100% 得到错误率。通常设置阈值如“大于 1% 触发告警”,避免单次抖动引发误报。
    E=NerrNtot×100%E = \frac{N_{err}}{N_{tot}} \times 100\%

6. 性能分析调优

同一个包裹从北京发往广州,中途要经过几个分拨中心。总送达时长并不是所有环节耗时的简单相加——有些环节可以并行,比如同时调用库存查询和优惠计算;真正决定总时长的,是那条最绕不开、必须一个个排队走完的串联路径。系统性能优化也是同一个道理:不能把每个服务都盲目调优一遍,而要找到那条决定响应时间的关键路径。

使用 Jaeger 做性能调优,第一步是“瓶颈定位”:在 UI 中打开一条慢请求的 Trace,瀑布图上每个 Span 的横向长度就是耗时,一眼就能看出哪个环节的条最长。第二步是“耗时分解”:点击慢 Span 查看其子 Span 和标签,判断耗时花在数据库查询、外部 HTTP 调用还是本地计算上。第三步是“关键路径分析”:区分串行与并行段——并行发出的子调用不叠加总时长,只有串行链路上各 Span 的耗时才逐个累加。

典型的优化方向包括:数据库慢查询加索引、外部 API 超时改为熔断降级、线程池排队导致的阻塞则考虑扩缩容或异步化。优化完成后,再次用 Jaeger 对比同一接口优化前后的瀑布图,看关键路径上的 Span 耗时是否下降——这比单纯看平均延迟更有说服力,因为你能直接看到“是哪一段路变快了”。

快递公司优化时效时,会优先优化中转次数最多的那条干线,而不是在每个站点“平均用力”。Jaeger 把你从“凭感觉调优”提升到“按关键路径调优”:哪些环节值得投入,哪些环节优化了也白费,瀑布图一摆,答案自然浮现。

Tresp=∑j∈CtjT_{resp} = \sum_{j \in \mathcal{C}} t_j
响应总时长等于关键路径上每个 Span 耗时之和。其中 $\mathcal{C}$ 表示关键路径上所有 Span 的集合,并行段只取最长者,而不是全部相加。
  1. 响应总时长$T_{resp}$ 表示用户感知到的端到端响应时间,也就是 Trace 根 Span 的耗时。
    TrespT_{resp}
  2. 关键路径集合$\mathcal{C}$ 是调用树中那些“一个等一个”的串联 Span 集合。找出它需要对瀑布图做路径分析,并行子调用不会全部叠加。
    C={串行链路上的 Span}\mathcal{C} = \{ \text{串行链路上的 Span} \}
  3. 求和$\sum_{j \in \mathcal{C}} t_j$ 把关键路径上每个 Span 的耗时累加。优化时优先削减集合中耗时最大的成员,效果最明显。
    Tresp=∑j∈CtjT_{resp} = \sum_{j \in \mathcal{C}} t_j

AI 应用场景

电商大促全链路应急响应

阶段:DevOps 监控告警与故障响应

解决的问题:大促期间订单服务响应变慢,传统方式只能登录各台服务器翻日志,难以判断瓶颈在订单服务自身还是下游的支付、库存依赖。Jaeger 通过一次请求的完整 Trace,直接把各服务耗时并列展示,让“哪里慢”一目了然。

具体案例:某电商团队在 618 大促当天收到“下单成功率降至 85%”的告警。运维人员登录 Jaeger 搜索失败 Trace,发现失败集中在支付回调环节,瀑布图显示某云厂商可用区的支付网关 P95 延迟高达 1.2 秒。团队随即对支付通道做切流,成功率在 15 分钟内恢复。整个过程验证了“告警触发 → Trace 定位 → 切流 → 再验证”的高效闭环。

微服务架构下的告警根因定位

阶段:根因分析与故障排查

解决的问题:Prometheus 告警能告诉你“订单服务错误率飙升”,却无法回答“错误来自哪个上游调用、失败在哪个下游依赖”。Jaeger 提供 Trace 维度,可在告警时按时间窗口反查调用链,从成千上万个 Span 中直接锁定报错的那一环。

具体案例:某团队收到“订单服务 5xx 增多”告警后,在 Jaeger 中按时间窗口检索错误 Span,发现 80% 的报错源于“库存服务连接池耗尽”,而库存服务 Pod 因内存 Limit 设置过小被频繁 OOMKill。调整资源配额后错误率归零,全程无需逐台登录服务器排查日志。

容量规划与采样策略调优

阶段:容量规划与成本控制

解决的问题:Jaeger 存储集群的成本随着业务量增长快速膨胀,如何在不损失关键链路可观测性的前提下控制成本?答案是使用采样公式 $C = N_r \times N_s \times p$ 做量化估算,并通过远程采样动态调整各业务线的采样率。

具体案例:某团队业务量翻倍后 Elasticsearch 集群写入压力大增。他们先将全局概率采样从 0.5 降到 0.2,存储写入压力下降 60%;同时通过远程采样对“支付”等高价值链路单独配置 1.0 采样,保证核心业务全链路可见,非核心业务则保持低采样率。一次调整既保住了成本,也保住了关键可观测性。

Python 演示

python57 行
import randomimport time  class Span:    def __init__(self, name, parent_id=None):        self.name = name        self.parent_id = parent_id        self.duration_ms = 0.0  class ProbabilisticSampler:    def __init__(self, rate=0.3):        self.rate = rate     def should_sample(self, trace_id):        return random.random() < self.rate  def trace_call_chain(services, sampler):    trace_id = random.randint(10000, 99999)    if not sampler.should_sample(trace_id):        return []    spans = []    parent_id = None    for name in services:        span = Span(name, parent_id)        start = time.monotonic()        time.sleep(random.uniform(0.005, 0.02))        span.duration_ms = (time.monotonic() - start) * 1000        spans.append(span)        parent_id = id(span)    return spans  def find_slow_span(spans):    if not spans:        return None    return max(spans, key=lambda s: s.duration_ms)  def main():    sampler = ProbabilisticSampler(rate=0.4)    services = ["gateway", "order", "payment", "inventory"]    all_spans = []    for _ in range(50):        all_spans.extend(trace_call_chain(services, sampler))    print("采样率40%下采集到的Span总数:", len(all_spans))    if all_spans:        slow = find_slow_span(all_spans)        print("最慢Span: %s, 耗时 %.2f ms" % (slow.name, slow.duration_ms))    total = sum(s.duration_ms for s in all_spans)    print("全部Span平均耗时: %.2f ms" % (total / max(len(all_spans), 1)))  if __name__ == "__main__":    main()
目的:用一个可运行的模拟程序演示 Jaeger 的两个核心机制——概率采样和 Span 父子链生成,并找出最慢的 Span,还原“链路追踪定位瓶颈”的基本思路。
  1. class Span:定义了追踪中的最小单元 Span,记录名称、父 Span 指向和耗时,对应正文中的“中转站扫描记录”。
  2. class ProbabilisticSampler:实现概率采样器,用 random.random() < self.rate 决定这条 Trace 是否被采集,体现“只为部分包裹装 GPS”的思想。
  3. parent_id = id(span)把上一个 Span 的对象 id 作为下一个 Span 的父指针,构造出父子调用链,对应 Trace 的树状结构。
  4. find_slow_span(all_spans)在所有 Span 中找出耗时最长者,模拟“瀑布图中一眼看到最长的红条”。
  5. if __name__ == "__main__":提供可执行入口,直接运行即可看到采样率和瓶颈定位的输出结果。

常见误区

误区我们已经上了 ELK 和 Prometheus,日志能看到错误堆栈,指标能看到 CPU 和延迟曲线,再上 Jaeger 是不是重复建设?

正解三者分工完全不同。日志是“离散事件流”,回答“这个服务刚才发生了什么”;指标是“聚合统计”,回答“系统整体健康吗”;追踪是“调用链上下文”,回答“一次请求穿越各个服务时,时间和错误花在了哪儿”。快递场景里,出库登记是日志,准时率报表是指标,全程物流轨迹才是追踪。没有追踪,你只知道包裹慢了,却不知道它卡在哪个中转站。

为何常见:因为三者都涉及“排查问题”,看起来功能有重叠,实际是从不同粒度回答不同问题。

误区追踪数据越全越好,我直接把采样率设为 1.0,这样任何请求都能查到链路,多花点存储算什么?

正解100% 采样在高并发下会产生海量数据,每秒 2 万条 Span 会让存储集群开销爆炸,最终导致追踪系统本身成为瓶颈。正确做法是按业务价值分级:核心交易链路用高采样率,非核心日志用低采样率,再叠加速率限制保护峰值。就像快递公司不会给每个包裹都装 GPS,只有贵重件才值得全程追踪。

为何常见:直觉上认为“数据全 = 洞察全”,忽略了分布式系统里数据量会随 QPS 和链路长度指数级放大。

误区Jaeger 瀑布图上那个最长的 Span 就是元凶,把它优化掉问题就解决了。

正解慢 Span 只是“现象发生的精确位置”,不是“原因”。支付服务耗时 1.2 秒,原因可能是下游数据库慢查询、CPU 争抢、线程池排队,甚至 GC 停顿。需要用 Span 的标签和日志结合代码上下文进一步分析,就像物流记录显示“包裹在华东分拨中心滞留 3 小时”——原因可能是货车晚点、设备故障,也可能是场地爆仓。

为何常见:瀑布图让问题定位变得非常直观,人们容易把“定位到环节”误认为“定位到根因”,忽略了根因分析还需要更多证据。

误区既然 Jaeger 能看到所有链路和错误,那我直接把告警规则配置在 Jaeger 上,省掉 Prometheus 和 Alertmanager 一套体系。

正解Jaeger 是分布式追踪系统,定位是“按 Trace 检索和展示调用链”,本身不做指标聚合和告警调度。正确的联动方式是:Jaeger 通过 spanmetrics 把追踪数据转换为 RED 指标,Prometheus 负责存储和计算告警规则,Alertmanager 负责发送通知。追踪系统和告警系统是“上下游协作”的关系,而非替代关系。

为何常见:把“能看到错误”误认为“能监控错误”,忽略了告警需要的持续聚合、阈值评估和事件路由能力。

面试题

Q1. 在 Jaeger 中,标识一次完整请求调用链的唯一编号是?

单选题 · easy

  • A.Span ID
  • B.Trace ID← 正确答案
  • C.Service ID
  • D.Pod ID

答案:B。Trace ID 是一次完整请求的唯一标识,类似物流单号,所有相关 Span 共享它。Span ID 只标识单个服务调用,Service ID 和 Pod ID 都不属于追踪系统概念。

Q2. Jaeger 中一个 Span 表示什么?

单选题 · easy

  • A.一条日志记录
  • B.一次服务调用的记录单元← 正确答案
  • C.一个 Kubernetes Pod 实例
  • D.一条 Prometheus 告警规则

答案:B。Span 描述一次服务调用(如“订单服务调支付服务”),记录起止时间、耗时、标签等信息,相当于物流轨迹中的一条中转扫描记录。日志、Pod、告警都不是 Span 的定义。

Q3. 概率采样器(probabilistic)的采样依据是什么?

单选题 · mid

  • A.请求耗时长短
  • B.固定时间间隔
  • C.随机抽样概率比例← 正确答案
  • D.服务名称的哈希值

答案:C。概率采样器按配置的概率 p 对每个 Trace 独立做随机抽样,如 p=0.1 表示约 10% 的请求被追踪。它与耗时、时间间隔、服务名无关,核心是用随机性保证样本的统计代表性。

Q4. 下列哪个可以作为 Jaeger 的存储后端?

单选题 · mid

  • A.MySQL
  • B.Elasticsearch← 正确答案
  • C.SQLite
  • D.Redis

答案:B。Jaeger 生产环境常用 Elasticsearch、Cassandra 等作为存储后端,它们适合大数据量写入和聚合查询。MySQL 和 SQLite 在官方支持列表之外,Redis 通常用作缓存而非持久化存储。

Q5. 下列哪些属于 Jaeger 的核心部署组件?

多选题 · mid

  • A.Agent 采集端← 正确答案
  • B.Collector 收集器← 正确答案
  • C.Prometheus 告警器
  • D.Query 查询服务← 正确答案

答案:ABD。Jaeger 四层架构是 Agent(采集)、Collector(汇聚接入存储)、Query(查询和 UI)、存储后端。Prometheus 是独立的监控告警系统,不属于 Jaeger 核心组件,但可与 Jaeger 集成。

Q6. 采样率设为 0.1,若每秒 1000 个请求、每个请求平均 20 个 Span,则每秒写入存储的 Span 数约为?

单选题 · hard

  • A.2000 条← 正确答案
  • B.10000 条
  • C.20000 条
  • D.100000 条

答案:A。用采样成本公式 C = N_r × N_s × p 计算:1000 × 20 × 0.1 = 2000 条/秒。这个数字是容量规划的基础,决定了存储集群的写入压力和成本预算。

Q7. RED 监控方法包含哪些核心指标?

多选题 · hard

  • A.Rate 请求速率← 正确答案
  • B.Errors 错误数← 正确答案
  • C.Duration 耗时分布← 正确答案
  • D.CPU 使用率

答案:ABC。RED 是微服务监控的黄金三角:Rate 看流量大小,Errors 看错误规模,Duration 看延迟分位数。CPU 使用率属于资源监控指标,不属于 RED 方法范畴。

Q8. 在 Jaeger UI 中查看一条 Trace 时,你能做什么?

单选题 · easy

  • A.查看调用链瀑布图和各 Span 耗时← 正确答案
  • B.修改微服务的业务代码
  • C.直接重启故障服务实例
  • D.删除数据库中的业务数据

答案:A。Jaeger UI 的核心能力是按 Trace 查看瀑布图、Span 耗时、标签与错误信息,帮助定位瓶颈。它不提供代码修改、服务重启或数据库操作能力,属于只读的观测工具。

Q9. 在分布式系统中,Span 的父子上下文通常通过哪些方式传递?

多选题 · mid

  • A.HTTP 请求 Header← 正确答案
  • B.消息队列消息 Header← 正确答案
  • C.gRPC Metadata 元数据← 正确答案
  • D.数据库表的主键字段

答案:ABC。Trace ID 和 Span ID 需要随请求在服务间传播,HTTP Header、消息队列 Header、gRPC Metadata 都是常见的传播通道。数据库主键用于业务关联,不承担链路上下文传递职责。

Q10. 在 Kubernetes 环境中,官方最推荐的生产级 Jaeger 部署方式是?

单选题 · extreme

  • A.手工编写大量 YAML 逐项部署
  • B.使用 Jaeger Operator 管理部署← 正确答案
  • C.使用 Docker Compose 单机部署
  • D.下载二进制在宿主机裸跑

答案:B。Jaeger Operator 基于 CRD 声明式管理完整生命周期,支持自动升级、伸缩和故障恢复,是 K8s 环境的最佳实践。手工 YAML 维护成本高,Docker Compose 适合本地开发,裸机部署则完全放弃了容器化优势。