想象你是警局新来的探员,深夜接到报案:订单系统大面积超时。你面前立着三个档案柜。第一个柜子是监控大屏,上面写着“下午 3 点某路口车流量暴涨 300%”——这是 Metrics(指标),它只告诉你总量趋势,不告诉你具体是哪辆车;第二个柜子是一沓目击者笔录,每张纸条写着“我看到一辆红车出现在银行门口”——这是 Logs(日志),每句话孤立无援;第三个柜子是一卷 GPS 轨迹,精确记录某辆车几点几分经过哪个路口——这是 Traces(链路)。 麻烦的是,三个柜子分属不同部门、不同系统。你要开三个软件查三套数据,而且它们“对不上号”:监控显示红车 3:02 经过路口,笔录却说红车 3:05 才到银行门口,你根本不确定这是不是同一辆车。这篇文章要讲的,就是怎么给每个请求发一张“车牌号”(Trace ID),再给所有记录贴统一的“描述标签”(Label),让监控、笔录、GPS 三份证据按同一个案子串起来查——这就是指标、日志、链路三大支柱的关联分析与统一查询。

岗位关联

学会用 Trace ID + Label 打通指标、日志、链路,你就能把排障从“来回切工具碰运气”变成“一条路径揪出根因”,这是 SRE 和故障排查工程师最值钱的手艺之一。

目录
  1. 可视化演示
  2. 三大支柱概览
  3. 割裂之痛
  4. Trace ID 关联
  5. Label 标签体系
  6. 统一查询方案
  7. 工具链落地
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示Metrics日志追踪通过TraceID关联传播、统一查询并行检索与排障流程全链路。

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

TraceID关联传播机制 请求经网关GW→S1→S2→DB,W3C TraceContext头传播trace_id Met/Log/Trc三支柱通过同一trace_id关联,实现跨数据源统一检索 trace_id=Span.trace_id W3C标准header实现跨服务trace_id自动传播

三大支柱概览

警局档案室里立着三个柜子。第一个柜子装满监控大屏截图:每个路口每分钟的车流量、平均车速、拥堵指数,唯独没有车牌号——这是 Metrics;第二个柜子是一沓目击者笔录:一条条零散的话,“3 点 02 分看见红车在银行门口”,却不知道它从哪来、要往哪去——这是 Logs;第三个柜子是一卷 GPS 轨迹,记录某辆车从出库到回库经过的每一个坐标点——这是 Traces。老探员带新人时总说:大屏告诉你“哪出事了”,笔录告诉你“事长什么样”,GPS 告诉你“事怎么发生的”。

放到可观测性领域,三大支柱就是这套配置。Metrics 指标是监控系统按固定间隔采集的数值序列,例如 QPS、错误率、P99 延迟,天生适合画曲线和告警;Logs 日志是服务打印的一行行文本,记录某个时刻发生了什么,适合全文检索;Traces 链路描述一次请求从入口到下游所有服务的完整调用树,适合看先后顺序和耗时分布。

三者的脾气完全不同。指标是“有损的”——采集时做了聚合,你只知道分位数,不知道具体是哪一个请求慢;日志是“无序的”——每行只说自己,不告诉你它属于哪次请求;链路是“昂贵的”——要为每个 span 记录起止时间和标签,全量存储成本很高。所以它们各有分工:指标负责发现,日志负责解释,链路负责串联。衡量一个服务健不健康,最常用的就是错误率:

三个柜子各有价值,但前提是它们得“对上号”。可现实里,它们根本对不上——这正是老探员最头疼的事。

error_rate=NerrorNtotal×100%\displaystyle \text{error\_rate} = \frac{N_{\text{error}}}{N_{\text{total}}} \times 100\%
错误率 = 出错样本数 ÷ 总样本数 × 100%,是三大支柱汇聚到同一时间窗口后首先要算的指标。
  1. 分子 N_error统计同一时间窗口内 level 字段为 error 的日志条数,代表出错的样本量。
    Nerror=∣{l∈Logs∣l.level=error}∣\displaystyle N_{\text{error}} = \left|\{ l \in \text{Logs} \mid l.\text{level} = \text{error} \}\right|
  2. 分母 N_total统计窗口内全部请求或日志的总条数,代表整体样本量。
    Ntotal=∣{r∈Requests∣t(r)∈[w0,w0+Δ]}∣\displaystyle N_{\text{total}} = \left|\{ r \in \text{Requests} \mid t(r) \in [w_0, w_0 + \Delta] \}\right|
  3. 乘 100%把比值换算成百分比,方便直接在监控面板上设置告警阈值。
    error_rate=NerrorNtotal×100%\displaystyle \text{error\_rate} = \frac{N_{\text{error}}}{N_{\text{total}}} \times 100\%

割裂之痛

现实里,三个柜子分属不同分局。监控大屏在交通科的系统里,笔录锁在刑侦队的柜子里,GPS 数据在网安平台的磁盘上。探员查个案要开三个软件、记三套账号、适应三套时间格式。更气人的是,大屏显示 15:02 路口流量异常,笔录写的却是 15:05 红车才出现,GPS 记录的是 15:03——你根本不知道哪条记录对应哪条,只能靠猜。

这就是三大支柱“割裂”的典型场景。生产环境里,Grafana 上的错误率曲线飙了;日志平台里躺着几亿行文本,你想搜却不知道关键词;链路平台里能看调用链,但你想知道这条链对应哪几行日志,得手动复制 trace_id 再切到日志平台重新搜一遍。每切一次工具,都要重设时间范围、重输过滤条件、重新在脑内拼接上下文。

割裂的代价是排障时间被切成一地碎片。指标平台发现异常、日志平台找证据、链路平台看路径、再回日志平台确认细节——这一圈绕下来,几十次切换轻轻松松。排障总耗时可以写成累加公式:

要打破这种局面,唯一的路是给三份证据发同一张“车牌号”——Trace ID,再贴同一套“描述标签”——Label。这就是接下来两节的主角。

T排障=∑i=1m(t切换,i+t检索,i)\displaystyle T_{\text{排障}} = \sum_{i=1}^{m} \left( t_{\text{切换},i} + t_{\text{检索},i} \right)
排障总耗时 ≈ 每次都“切工具 + 重新检索”的成本之和,工具越割裂、次数越多,耗时就越长。
  1. 交替求和一次完整排障由 m 次“工具切换 + 数据检索”组成,总耗时是各段之和。
    ∑i=1m\displaystyle \sum_{i=1}^{m}
  2. 切换成本每次从指标切到日志再切到链路,都要重新输时间范围、过滤条件、登录账号。
    t切换,i\displaystyle t_{\text{切换},i}
  3. 检索成本在新工具里重新输入关键词、翻页、滚动,把上一步的上下文再拼回来。
    t检索,i\displaystyle t_{\text{检索},i}

Trace ID 关联

老探员后来定了个规矩:每辆车出库时都要登记车牌号,之后的每一个路口记录仪、每一份笔录、每一段 GPS 轨迹,都必须带上这个车牌号。这样一来,“车牌号”就成了三个柜子共用的案卷编号。你说“查 15:03 从东门出去的那辆红车”,三份资料能同时翻出来对质。

在分布式系统里,这个“车牌号”就是 Trace ID。一次用户请求进来,网关生成一个全局唯一的 Trace ID,然后通过 HTTP header(如 traceparent)在调用链的每个服务之间传递。下游服务收到后,把它写进自己的日志、指标标签和链路 span。于是,三类数据从诞生那一刻起就带着同一个 ID,像三份证据盖上了同一个案卷章。

但链路不是一条平铺的线,而是一棵树。每个服务执行的一段工作叫 span(跨度),span 之间有严格的父子关系:入口 span 是树根,它发起的 RPC、SQL、消息队列调用是子 span。父 span 从开始到结束的耗时区间,一定完整覆盖所有子 span 的区间,这是判断链路结构是否合法的关键:

有了 Trace ID 这棵“调用树”,日志和指标都有了归属。但车管所只发车牌号还不够:探员要按“红色、中型、周五下午”这种描述批量筛车,还得给数据统一贴标签。

Dparent⊇⋃i=1nDspan,i\displaystyle D_{\text{parent}} \supseteq \bigcup_{i=1}^{n} D_{\text{span},i}
父 span 的耗时区间必须包含全部子 span 区间的并集,否则就说明链路数据有缺失或埋点有 bug。
  1. 子 span 区间链路上每个下游调用的耗时区间,从开始时刻到结束时刻。
    Dspan,i=[si,ei]\displaystyle D_{\text{span},i} = [s_i, e_i]
  2. 取并集全部子 span 覆盖的时间范围,反映所有并行子任务合计占用的时间。
    ⋃i=1nDspan,i\displaystyle \bigcup_{i=1}^{n} D_{\text{span},i}
  3. 包含关系父 span 从入口到出口完整包住所有子 span,这是链路树合法的判定条件。
    Dparent⊇⋃i=1nDspan,i\displaystyle D_{\text{parent}} \supseteq \bigcup_{i=1}^{n} D_{\text{span},i}

Label 标签体系

车牌号是一车一码,可排查问题时你往往还不确定是哪辆车,只记得“红色、从东门进来的、周五下午”。老探员于是设计了标准描述卡:颜色、车型、入门时间、所属车队……每份证据都按这张卡填写。想查的时候,按卡片上的任意几项组合筛选,三个柜子都能用同一套筛选词。

对应到可观测性,这张“描述卡”就是 Label 标签体系,本质是键值对。常见标签有 service(服务名)、env(环境)、version(版本)、region(机房)、k8s_pod(实例)。Metrics 天生带 label 和 time series;Logs 可以在采集时给每行附加结构化标签;Traces 的每个 span 身上也有 resource attributes。三者在标签词表上对齐,是关联查询的地基。

标签体系的核心价值是“统一过滤”:三个数据源共享同一份标签语义,查询时指定服务名、环境、版本,三类数据各自按相同条件过滤,再通过 Trace ID 关联。用集合语言描述,就是在所有“事件”里筛出“标签集合完整命中查询条件”的那一批:

注意,标签不是越多越好。把每次请求的唯一 ID 当标签贴上去,会造成“高基数爆炸”,把存储压垮。标签要选 service、env、version 这类低基数资源维度,高基数的唯一 ID 交给 Trace ID 区承担——这就是档案分类学的精髓:统一的描述词,但不能乱贴词。

Q(L)={e∈E∣L⊆labels(e)}\displaystyle Q(L) = \{ e \in E \mid L \subseteq \text{labels}(e) \}
查询结果 = 所有标签集合包含查询标签的事件,指标样本、日志行、链路 span 都统一看成“带标签的事件”。
  1. 事件全集 E三类数据被统一抽象成“事件”,指标样本、日志行、链路 span 都是事件。
    E=Emetrics∪Elogs∪Espans\displaystyle E = E_{\text{metrics}} \cup E_{\text{logs}} \cup E_{\text{spans}}
  2. 每条数据的标签labels(e) 是附加在事件上的键值对集合,例如 service=order-svc。
    labels(e)={(k1,v1),(k2,v2),… }\displaystyle \text{labels}(e) = \{ (k_1,v_1), (k_2,v_2), \dots \}
  3. 子集包含过滤查询标签集合 L 必须被事件的标签集合完整包含,该事件才会被选中。
    L⊆labels(e)\displaystyle L \subseteq \text{labels}(e)

统一查询方案

有了车牌号和描述卡,老探员还差一样东西:一个统一的检索台。以前三个系统各查各的,现在他希望在一个输入框里输入“周五下午 + 红色 + 东门”,三份档案一次性返回,能从一份证据跳到另一份,全程不换软件。

统一查询的落地形态通常是:指标、日志、链路三套数据仍由各自的引擎存储——Prometheus 存指标、Loki 存日志、Tempo 存链路——但它们共享同一套标签语义和同一个查询入口(Grafana Explore)。排查时先看指标曲线,发现异常后顺着 label 和时间窗“钻取”(drill-down)到日志,再从日志里的 trace_id 一键跳进链路视图。

这里最关键的技术点是时间对齐。三条数据源的时间戳粒度不同,必须锁定同一时间窗口 [w0, w0 + Δ],否则跳转过去看到的不是同一段现场。同时要理解三套查询语法的关系:PromQL 查指标、LogQL 查日志、TraceQL 查链路,它们针对同一组 label 和 trace_id 协同工作。例如“订单服务在故障窗口的 P99 延迟”,本质是这样一个查询:

排障由此变成一条顺畅的流水线:指标报警 → 定位服务 → 钻取日志 → 提取 trace_id → 展开调用树 → 找到问题 span → 回看该 span 的日志与指标。老探员终于不用在三个软件之间来回横跳了。

P99w=percentile(Dw(L), 0.99)\displaystyle \text{P99}_w = \text{percentile}\bigl( D_w(L),\, 0.99 \bigr)
P99 查询 = 先按标签集合 L 和时间窗 w 筛出样本,再对耗时排序取第 99 百分位。
  1. 数据窗口只保留标签满足 L、时间戳落在窗口 w 内的样本。
    Dw(L)={d∣labels(d)=L, t(d)∈w}\displaystyle D_w(L) = \{ d \mid \text{labels}(d) = L,\ t(d) \in w \}
  2. 排序取分位把窗口内样本按耗时升序排列,取第 99 百分位,即 99% 的请求都比它快。
    percentile(Dw(L),0.99)\displaystyle \text{percentile}(D_w(L), 0.99)
  3. 组合语义这个表达式把“标签过滤、时间对齐、分位计算”三步压缩成一次统一查询。
    P99w=percentile(Dw(L), 0.99)\displaystyle \text{P99}_w = \text{percentile}\bigl( D_w(L),\, 0.99 \bigr)

工具链落地

光有理论还不够。老探员向局里申请了一套标准装备,把三个独立系统统装进一个平台。开源领域最经典的组合是 Grafana 全家桶:Prometheus 负责指标、Loki 负责日志、Tempo 负责链路,三者作为数据源接入 Grafana,在 Explore 页面里互联互通。

整套工具链打通的关键动作有三个。第一,所有服务接入同一个 OpenTelemetry SDK,自动生成 trace 并注入 trace_id;第二,日志采集端把 trace_id 和标准化标签写进每一行,让日志与链路共享标识;第三,在指标面板上配置数据源链接(datasource links),从指标点直接跳到同一时间窗的日志和链路,实现“点一下就能钻取”。

最后一道坎是成本。链路数据全量保存非常贵,必须做采样。采样的核心逻辑是:用存储预算除以单条链路的平均成本,比值大于 1 就全量保存,不足 1 就按比例降采样;同时为了不丢失“报错请求”这类高价值链路,通常对 error span 单独提高采样权重:

装备到位、规则定好、成本算清,这个“统一档案室”才算真正落地。从此排障不再是三个孤岛间的漫长跋涉,而是一条从指标到日志再到链路的直达通道——老探员终于可以准时下班喝茶了。

rsample=min⁡(1, BbudgetNreq×bavg)\displaystyle r_{\text{sample}} = \min\Bigl(1,\, \frac{B_{\text{budget}}}{N_{\text{req}} \times b_{\text{avg}}}\Bigr)
采样率 = 存储预算 ÷(请求总数 × 单链路平均成本),超过 1 就取 1(全量),不足 1 就按比例降采样。
  1. 全量成本请求总数乘以单条链路的平均存储开销,得到“一条不落”需要的总空间。
    Nreq×bavg\displaystyle N_{\text{req}} \times b_{\text{avg}}
  2. 预算约束采样率等于存储预算与全量成本的比值,反映能存下多大比例。
    BbudgetNreq×bavg\displaystyle \frac{B_{\text{budget}}}{N_{\text{req}} \times b_{\text{avg}}}
  3. 截断到 1比值超过 1 说明预算够,取 1 代表全量采样;不足 1 则按比值降采样。
    min⁡(1, BbudgetNreq×bavg)\displaystyle \min\Bigl(1,\, \frac{B_{\text{budget}}}{N_{\text{req}} \times b_{\text{avg}}}\Bigr)

AI 应用场景

大促峰值订单超时定位

阶段:故障定位与根因分析(可观测性建设)

解决的问题:传统方式下,监控告警、日志检索、链路追踪三个工具彼此独立,SRE 接到告警后要先登 Grafana 看指标,再切到日志平台搜关键词,再切到链路平台找 span,平均定位耗时 2 小时以上。打通后,从指标面板点击异常点,系统自动带入同一时间窗和相同 label,关联出对应 Trace ID,再展开调用树和日志,全程一个界面。

具体案例:某电商 SRE 在大促压测时发现支付成功率跌了 5%,顺着指标钻取到日志,看到大量 payment timeout,再点进链路发现是“支付回调 + 库存扣减”组合调用的等待时间异常,迅速锁定了刚上线的缓存策略改造,回滚后 10 分钟恢复。

慢接口性能劣化分析

阶段:性能分析与容量评估

解决的问题:接口 P99 上涨时,无法快速判断瓶颈在哪个下游。利用统一查询,先看指标曲线确认劣化时段,再按 service 和 version 标签过滤出该时段的链路,找到最慢的 span,最后关联该 span 的日志确认是数据库连接池等待还是外部依赖超时。

具体案例:某团队发现订单查询接口 P99 从 80ms 涨到 500ms,通过链路发现耗时集中在 user-svc 的一个 Redis 调用上,日志显示 connection refused 频繁出现,最终定位为 Redis 连接池配置过小,调整后恢复。

发布灰度回归对比

阶段:变更评估与回归验证

解决的问题:版本发布后如何快速判断新版本带来了多少错误和延迟。利用 version=v2.3 与 version=v2.2 两个标签做对比查询,指标、日志、链路三个数据源共享同一套标签,一键拉出新旧版本的错误率、报错日志类型和链路耗时分布。

具体案例:某团队灰度发布 v2.3 后,统一查询发现新版本的 GET /cart 接口错误率是旧版本 3 倍,日志显示 NPE 堆栈,链路显示异常集中在缓存反序列化 span,立即停止灰度并回滚。

Python 演示

python53 行
# -*- coding: utf-8 -*-"""三大支柱关联查询演示:用 Trace ID 把指标、日志、链路撮合到同一条记录"""from collections import defaultdict  def gen_data():    services = ['api-gateway', 'order-svc', 'pay-svc']    traces, logs = [], []    for i in range(6):        tid = 'trace-%d' % (5000 + i)        for s in services:            is_error = (i % 3 == 2 and s == 'pay-svc')            traces.append({                'trace_id': tid,                'service': s,                'dur_ms': 30 + i * 10,                'error': is_error            })            logs.append({                'trace_id': tid,                'service': s,                'level': 'ERROR' if is_error else 'INFO',                'msg': 'payment timeout' if is_error else 'ok'            })    return traces, logs  def correlate(traces, logs, trace_id):    """按 trace_id 做关联:返回该请求的完整链路与日志"""    spans = [t for t in traces if t['trace_id'] == trace_id]    log_lines = [g for g in logs if g['trace_id'] == trace_id]    return {'trace_id': trace_id, 'spans': spans, 'logs': log_lines}  def main():    traces, logs = gen_data()    failed_ids = []    for t in traces:        if t['error'] and t['trace_id'] not in failed_ids:            failed_ids.append(t['trace_id'])    print('按 Trace ID 关联查询,失败请求:')    for tid in failed_ids:        rec = correlate(traces, logs, tid)        print(rec['trace_id'], 'spans=%d logs=%d' % (len(rec['spans']), len(rec['logs'])))        for sp in rec['spans']:            print('  span:', sp['service'], sp['dur_ms'], 'ms', 'ERR' if sp['error'] else 'OK')        for lg in rec['logs']:            if lg['level'] == 'ERROR':                print('  log :', lg['service'], lg['msg'])  if __name__ == '__main__':    main()
目的:模拟三个服务产生的链路与日志数据,演示如何用 Trace ID 把零散数据关联成一份完整故障现场。
  1. tid = 'trace-%d' % (5000 + i)生成一个全局唯一的 Trace ID,相当于给请求发“车牌号”
  2. is_error = (i % 3 == 2 and s == 'pay-svc')每隔 3 个请求让 pay-svc 那一段报错,模拟故障注入
  3. traces.append({'trace_id': tid, ...})写入一条 span 记录,相当于 GPS 轨迹中的一个坐标点
  4. logs.append({'trace_id': tid, ...})写入一条日志,同时携带 trace_id,相当于笔录盖案卷章
  5. spans = [t for t in traces if t['trace_id'] == trace_id]按 Trace ID 关联出该请求的全部 span
  6. log_lines = [g for g in logs if g['trace_id'] == trace_id]按 Trace ID 关联出该请求的全部日志
  7. if t['error'] and t['trace_id'] not in failed_ids:遍历找出报错的 Trace ID 并去重
  8. rec = correlate(traces, logs, tid)把链路和日志撮合成一份故障档案
  9. if __name__ == '__main__': main()标准入口,保证脚本可直接运行

常见误区

误区只要在日志里加上 trace_id,排障时 grep 一下就能找到所有数据,任务就完成了。

正解Trace ID 只是“骨架”,完整的关联还需要 span 的父子结构、时序关系和统一的 Label 标签体系。只有 ID 而没有 span 树和标签语义,你只能知道“这行日志属于某次请求”,却不知道它在调用链的哪一环、前后发生了什么。车牌号得配上行车轨迹和描述卡才能真正破案。

为何常见:很多团队第一步就是给日志加 trace_id,改造最小、见效最快,容易让人误以为这就是关联的全部。

误区监控指标已经很全了,曲线、告警、仪表盘都有,出问题看指标就够了,日志和链路可有可无。

正解指标是聚合有损的,P99 涨了只告诉你“变慢了”,不告诉你哪一行代码出错、哪一次调用超时。指标负责缩小范围,日志负责给证据,链路负责还原路径,三者是分工关系而不是替代关系。监控大屏看到的“车流量暴涨 300%”和“到底是哪辆车闯的祸”是两回事。

为何常见:指标可视化最直观、告警最及时,容易产生“监控即一切”的错觉,忽视了聚合过程丢掉的单请求细节。

误区链路数据全量采集才安心,反正磁盘便宜,采样率拉满,一条都不丢。

正解全量链路的内存和存储成本极高,高峰期可能把存储系统压垮。正确做法是按价值采样:高价值请求(报错、慢请求、核心链路)提高采样权重,普通请求按预算降采样。采样率公式的本质是“预算 ÷ 总成本”,控制住成本才能长期稳定运行。

为何常见:故障排查最怕“恰好没采到那一次”,这种恐惧让人忽略成本和收益的平衡,结果反而因存储故障制造新的故障。

误区把三套开源组件都部署起来,统统接进 Grafana,就算三大支柱关联完成了。

正解三个系统放在同一个 Grafana 页面里,只是“物理聚集”,不是“逻辑关联”。要真正打通,还需要统一标签词表、统一时间对齐、配置数据源链接跳转、规范 trace_id 注入。否则你依然是一个个面板依次打开,手动复制 ID 再搜索,和之前没有本质区别——三份档案放在同一间屋子却各自锁在独立抽屉里。

为何常见:工具堆叠的成果肉眼可见,Grafana 里一排数据源让人产生“已经一体化”的错觉,忽略了数据语义层面的打通才是关键。

误区给数据多贴标签,以后想怎么查都行,label 多多益善。

正解标签体系的铁律是“低基数”:service、env、version 这种取值有限的维度适合做标签,而每次请求都不同的唯一 ID 属于高基数,一旦当标签写入,会导致时间序列爆炸、存储飙升、查询变慢。唯一 ID 应该放在 Trace ID 字段里,而不是塞进 label。描述卡上的词要固定有限,不能把车牌号也当成描述词。

为何常见:Prometheus 的 label 模型深入人心,但很多人没意识到它“基于标签寻址存储”的特性,把高基数数据扫进去才发现存储崩溃。

面试题

Q1. 可观测性三大支柱通常指什么?

单选题 · easy

  • A.Metrics、Logs、Traces← 正确答案
  • B.CPU、内存、磁盘
  • C.容器、K8s、微服务
  • D.开发、测试、运维

答案:A。三大支柱是 Metrics(指标)、Logs(日志)、Traces(链路),分别对应监控大屏、目击者笔录、GPS 轨迹。CPU/内存/磁盘是服务器资源维度,容器/K8s/微服务是架构技术,开发/测试/运维是角色分工,都不是可观测性数据的三大分类。

Q2. Metrics 指标最主要的特点是什么?

单选题 · easy

  • A.聚合数值且丢失细节← 正确答案
  • B.保留每次请求原样
  • C.记录全部业务文本
  • D.仅保存二进制对象

答案:A。指标采集时按时间窗口做聚合(计数、平均、分位),所以是有损的——像监控大屏只告诉你流量暴涨,不告诉你具体是哪辆车。选项 B 是日志/链路的能力,C 是日志的特征,D 与指标无关。

Q3. Trace ID 的核心作用是什么?

单选题 · mid

  • A.串联一次请求的全部数据← 正确答案
  • B.替代密码做服务鉴权
  • C.压缩指标数据的体积
  • D.随机生成并写入数据库

答案:A。Trace ID 像车牌号,从请求入口生成后贯穿所有服务,让指标、日志、链路三类数据都能按它聚合。它不负责鉴权,不压缩数据,也不是为了写数据库而存在——它存在的意义是让分散的记录“对得上号”。

Q4. 关于 Span 父子关系正确的是什么?

单选题 · mid

  • A.父 Span 覆盖全部子 Span← 正确答案
  • B.子 Span 覆盖全部父 Span
  • C.父子 Span 之间没有关联
  • D.父子 Span 必须同时结束

答案:A。父 span 是入口,它调用的下游任务是子 span,父 span 的耗时区间必须完整包含所有子 span 区间的并集,否则链路结构不合法。子 span 不可能覆盖父 span,父子必然有包含关系,也无需同时结束(子 span 可能并行)。

Q5. 关联三大支柱需要哪些关键手段?

多选题 · mid

  • A.统一 Trace ID 贯穿← 正确答案
  • B.统一 Label 标签体系← 正确答案
  • C.统一查询入口跳转← 正确答案
  • D.只靠时间戳就能关联

答案:ABC。Trace ID 负责把分散数据串成一份档案,Label 负责跨源统一过滤,统一查询入口负责钻取跳转,三者缺一不可。只靠时间戳不行:高并发下同一毫秒有成千上万个请求,没有 ID 和标签根本区分不开,就像没有车牌号和时间对齐,监控与笔录永远对不上。

Q6. 在 Grafana + Loki + Tempo 组合中,Loki 主要负责什么?

单选题 · mid

  • A.集中存储与检索日志← 正确答案
  • B.采集指标时序数据
  • C.生成链路追踪数据
  • D.执行业务 SQL 查询

答案:A。Loki 是日志存储与检索系统,对应“目击者笔录柜子”;Prometheus 负责指标时序数据,Tempo 负责链路追踪数据,Grafana 负责统一展示与跳转。链路数据由 OpenTelemetry 埋点生成,不是 Loki 的职责。

Q7. 关于头部采样与尾部采样,正确的说法是什么?

单选题 · hard

  • A.先采样再看结果,可能漏错← 正确答案
  • B.先采样再看结果,保住错误
  • C.两者都会丢弃全部数据
  • D.两者等价没有任何差异

答案:A。头部采样在请求刚进来时就决定采不采集,那时还不知道结果,可能漏掉最后才报错的慢请求;尾部采样等请求结束、知道了成败再决定,能保证留下错误链路,但需要短暂缓冲。两者有明显差异,且都不是全丢或全留,所以 B、C、D 都错。

Q8. 统一查询时为什么必须做时间对齐?

多选题 · hard

  • A.跨数据源时间窗口一致← 正确答案
  • B.链接指标异常与日志根因← 正确答案
  • C.防止查询结果错位误判← 正确答案
  • D.可以让指标数据变小

答案:ABC。指标、日志、链路的时间戳粒度不同,只有锁到同一时间窗口,才能保证从指标点钻取到的日志和链路是同一段现场,否则会错位误判——就像监控显示 15:02 异常、笔录写 15:05,对不上时间就破不了案。时间对齐不会改变数据体积,所以 D 错误。

Q9. Prometheus 存储的核心数据是什么?

单选题 · easy

  • A.指标与标签时序数据← 正确答案
  • B.非结构化文本日志
  • C.服务调用链路图谱
  • D.关系型业务数据表

答案:A。Prometheus 存的是带标签的指标时序数据,按指标名 + label 组合寻址。非结构化日志归 Loki,链路图谱归 Tempo,关系型业务表归数据库——各有分工,不要混为一谈。

Q10. 应用侧埋点改造的落地规范包括哪些?

多选题 · hard

  • A.统一注入 Trace ID← 正确答案
  • B.统一服务名与标签← 正确答案
  • C.制定合理采样策略← 正确答案
  • D.日志全部改成大写

答案:ABC。落地规范的核心是:接入 OpenTelemetry 统一注入 Trace ID,统一服务命名和低基数标签(service/env/version),并制定采样策略控制成本。日志大小写与关联查询无关,属于无效改动,故 D 错误。