想象你从网上下单一双球鞋,包裹从广州仓库出发,途经华南分拣中心、华东转运站,最后抵达你家楼下的快递驿站。你不需要挨个给每个站点打电话,只需要打开物流 App,输入运单号,就能看到包裹完整的轨迹:什么时间到了哪里、谁签收、停留了多久。 在云原生世界里,一次用户请求就像这个包裹——你点下“提交订单”,前端服务会调用网关,网关调用认证服务,认证服务又调用订单服务,订单服务还要调支付和库存……每个微服务就像一个分拣中心,每个服务处理的一小段工作就像一次扫码记录。Tempo 就是那个物流查询系统:只要拿到一个“运单号”(Trace ID),就能把散落在各个服务里的碎片信息串成一条完整的请求轨迹,一秒钟定位到“包裹”到底卡在了哪个环节。 这篇文章会带你把 Tempo 这个分布式追踪平台彻底搞懂:从 Trace 和 Span 这对基础概念,到它内部的组件架构、存储索引、查询语言 TraceQL,再到与 Grafana 和 OpenTelemetry 的配合,以及真实生产中的性能优化和排障实践。
对 AI 从业者而言,分布式追踪是理解云原生基础设施的必备技能。掌握 Tempo,你就能在模型服务、推理链路出现性能瓶颈时,像查物流一样快速定位问题,真正具备系统性排障的工程能力。
目录
可视化演示
展示Distributor到Querier的Trace处理流水线、网关订单库存支付微服务调用链诊断、以及Resource到Span的Trace数据模型层级。
本节配有交互动效(进入视口后自动加载,约 3KB)。
Tempo Trace处理流水线 Distributor分发Ingester写入 Compactor压缩Querier查询 Dis→Ing→Cmp→Que 只索引TraceID其余存对象存储
追踪基础概念:从运单号到完整轨迹
你寄出的每一件快递外包装上,都贴着一张运单号。这个号码会跟随包裹走过所有分拣中心。每到一个站点,扫描枪“嘀”一声,一条包含时间、站点、操作员的记录就会上传到物流系统。整段旅程的所有记录放在一起,就是这条快递的完整轨迹;而每一条单独的扫码记录,就是轨迹上的一个点。
在微服务架构中,一次用户请求从进入系统到返回响应,会依次调用多个服务。我们把这个完整过程称为 Trace(追踪链路),它对应物流系统中的“完整轨迹”。链路中的每一个服务调用、每一次内部处理,都是一个 Span(跨度),它对应“一次扫码记录”。每个 Span 都携带同一个 Trace ID(追踪标识符),相当于运单号;同时记录自己的 Span ID 和 Parent Span ID,用父级关系把众多 Span 组织成一棵调用树。
下面这个数据结构描述了一个 Span 的灵魂:
如果前端调用网关花了 30ms,网关调用订单服务又花了 80ms,这些数字就像包裹在每站停留的时长。把同一运单号的所有扫码记录按时间轴排开,哪一段拖了后腿就一目了然。Tempo 做的,正是把这张“运单号”对应的全部扫码记录从海量数据中捞出来,拼成一个可读的瀑布图。
- trace_id(运单号)这是全链路共用的标识,Trace 内每一个 Span 都携带同一个 trace_id,负责把碎片串成整体。
- span_id(本环节回执号)每个 Span 自己独有的编号,用来唯一标识这一次服务处理行为。
- parent_id(上一站编号)记录调用来源对应的 span_id,根 Span 的 parent_id 为空;通过它构建树形调用关系。
- service(服务名)标明这段处理发生在哪个微服务中,帮助你在追踪时快速区分环节。
- start_time / duration(开始与耗时)记录处理开始时刻与持续时长,是计算链路瓶颈的核心数据。
Tempo 架构组件:物流中心的分工协作
一个大型物流中心不会只有一个人在干活:有调度员把新到的包裹分派给不同窗口,有前台收件员快速录入信息,有理货员把散装小件合并成整箱,还有查询客服专门应对“我的包裹到哪了”的问题。Tempo 的架构也是同一套分工逻辑。
Tempo 内部由四个核心组件协作完成追踪数据的处理。Distributor(分发器) 是调度员,负责接收上报的 Span 数据,并按规则把属于同一条 Trace 的数据路由到同一个 Ingester(写入器);Ingester 是前台收件员,负责接收并暂存最新的追踪数据;Compactor(压缩器) 是理货员,定期把小块数据合并成大块,减少存储碎片;Querier(查询器) 是查询客服,响应你输入的 Trace ID 或查询条件,从存储中找回完整链路。
那 Distributor 怎么确保同一条 Trace 的所有 Span 都进入同一个 Ingester 呢?它用了一个非常稳定的哈希算法:
这个设计就好像物流调度员看到同一个运单号就固定分配给同一号收件窗口,这样当你查询时,只需要找那一个窗口就能拿到整段记录,而不必跑遍所有窗口拼凑信息。Ingester 先把数据留在内存,Compactor 后台再去整理归档,职责分离让整个系统忙而不乱。
- hash(指纹函数)把任意长度的 Trace ID 映射成一个整数指纹,相同输入永远得到相同输出。
- mod N(取余落位)对 Ingester 数量 N 取余,得到的余数就是目标 Ingester 的编号。
- 稳定路由同一条 Trace 的每个 Span 都携带相同 Trace ID,因此永远落到同一个 Ingester,查询时无需跨节点拼接。
存储与索引:仓库里的纸箱与门口筛查员
物流仓库里,包裹不会散落一地,而是被装进一个个标准纸箱,按批次码放在货架上。Tempo 的存储设计也遵循同样的思路:它把追踪数据写入 对象存储(S3、GCS、Azure Blob 等),里面以 Block(数据块) 为基本单位组织数据。每个 Block 装着一段时间范围内的很多 Trace,就像一箱装了很多包裹。
但仓库那么大,找一件包裹不能把每个纸箱都拆开翻一遍。Tempo 的做法是:给每个 Block 的门口配一位 Bloom Filter(布隆过滤器)——它不存储具体数据,只回答一个问题:“这个 Trace ID 可能在这个 Block 里吗?”如果回答“不可能”,就跳过整个 Block;如果回答“可能”,再进 Box 里精确查找。
Bloom Filter 的判断逻辑可以这样理解:
这种设计让 Tempo 检索海量 Block 时可以快速跳过绝大多数不相关数据。你输入一个 Trace ID,Tempo 会先查每个 Block 门口的“筛查员”,只对可能包含该 Trace 的 Block 做精确查询。牺牲极小的误判概率,换来数量级的检索加速——这就像仓库门口筛查员如果看到运单号数字特征对不上,直接摆手放行,省去拆箱的工夫。
- h_i(x)(第 i 个哈希函数)对 Trace ID x 做 k 次不同哈希,每次都定位到位数组 B 中的一个位置。
- B[……](位数组取值)Block 的 Bloom Filter 由 m 个二进制位组成,B[j] 表示第 j 位是否为 1。
- ∧(与运算)只有当 k 个位置全部为 1,才判定“可能存在”,否则直接判定“不存在”。
查询机制:TraceQL 与按 ID 秒查
当客服在物流系统里输入运单号,系统几乎瞬间就能返回结果。Tempo 的查询也分两条路径:如果你知道确切的 Trace ID,那就是“按单号查”,走最快路径;如果你只记得“寄件人、包裹类型、日期”这些模糊信息,就得用高级搜索语句——TraceQL。
TraceQL 是 Tempo 推出的结构化查询语言,让你不用知道 Trace ID 也能筛选链路。它支持按服务名、Span 属性、持续时间等条件过滤。比如你想查“order 服务中耗时超过 100ms 的 Span”,一行 TraceQL 就能表达这种组合条件。查询器拿到条件后,需要扫描哪些 Block、跳过哪些 Block,同样依赖索引和 Bloom Filter 做初步筛选。
一次典型查询的耗时可以被拆解成下面这个量级:
有 Trace ID 时,Tempo 会先把 ID 映射到具体 Block(过程接近 O(1)),再用 Bloom Filter 确认,最后在块内二分定位。整套流程下来,查询通常在几十毫秒内完成。就像客服不用翻遍全城仓库,只凭系统里记录的“运单号在 3 号仓 5 号箱”,直奔目标即可。
- B_c(候选 Block 数量)Bloom Filter 帮你把海量 Block 缩小到极少数“可能存在”的候选块,B_c 通常接近 1。
- log₂(二分查找)Block 内部按 Trace ID 有序存储,可以用二分查找快速定位目标。
- F(过滤器判定)Bloom Filter 的每次判定是常数级的位运算,F 表示这部分的固定开销。
Grafana 集成:一张面板看全链路
有了物流系统还不够,用户还得有个方便查看的 App 界面。在可观测性领域,Grafana 就是那个统一的“物流 App”。通过把 Tempo 配置为 Grafana 的数据源,你可以在同一条时间线里把指标(Metrics)、日志(Logs)和追踪(Traces)关联起来——业内称为“三合一可观测性”。
Grafana 里查看 Tempo 数据时,最常见的视图是 瀑布图(Waterfall):横轴是时间,纵轴是服务调用层级,一层层的 Span 条像瀑布一样铺开,慢 Span 会用醒目的红色标出。你可以从一条 Trace 直接下钻到某个 Span,查看它的标签、日志和耗时详情。反过来,你也能从一条异常日志或一个指标告警,跳转到关联的 Trace 上下文。
这种关联的本质,是让不同信号源共享同一个关联键:
这条公式想表达的是:当你在 Grafana 看到某个服务延迟告警,点击“查看关联 Trace”就能看到该时段对应的完整调用链,再点开具体 Span 就能看到当时打印的日志。追踪不再是孤岛,而是和指标、日志连成一体的作战地图。好比物流 App 上,你既能看运单轨迹,也能看派送员留言,还能看哪个地区的配送整体超时——所有信息围绕同一个运单号组织起来。
- span 与 log/metric(信号源)Span 记录链路结构,日志记录详细事件,指标记录聚合计数,三者描述同一件事的不同侧面。
- bowtie(关联连接)数据库中的连接操作,表示按某个共同字段把不同表拼接起来。
- trace_id(关联键)三种数据都携带同一个 trace_id,Grafana 据此把它们串成同一条上下文。
OpenTelemetry 采集:贴面单与扫码上传
物流系统能查到轨迹的前提,是每个分拣中心都认真扫码上传。对应到分布式系统,就是每个服务都要主动“埋点”,把自己的处理信息上报给 Tempo。这项采集工作,业界标准方案是 OpenTelemetry。
OpenTelemetry 提供统一的 SDK 和 API,支持 Java、Go、Python、Node.js 等几乎所有主流语言。它会自动拦截服务之间的 HTTP/gRPC 调用,自动生成 Span 并填充 trace_id 和 parent_id,然后通过 OTLP(OpenTelemetry Protocol) 上报到 Tempo。传输方式可选 gRPC 或 HTTP,gRPC 适合内网高性能场景,HTTP 更灵活、便于穿透各种网络环境。
生产环境中,高并发服务的 Span 数量极其庞大。如果每一个请求都完整上报,存储成本会迅速失控。因此 OpenTelemetry 提供了采样机制,最简单的头部采样可以表示为:
采样就像物流公司对“同城速递”只看抽样单:不是每一单都会全程跟踪,而是按照 10% 的比例抽取面单,既保证能发现普遍问题,又不至于让追踪系统的仓库被塞爆。等出了问题,再针对性调高采样率做细查。
- random()(随机数生成)每次请求生成一个 0 到 1 之间的均匀随机数,作为采样骰子。
- p(采样率)0 到 1 之间的阈值,p=0.1 表示平均只保留 10% 的请求链路。
- keep 判定(是否保留)随机数小于 p 就保留该 Trace,否则丢弃,统计上保留比例近似于 p。
性能与优化:控制成本与加速查询
物流公司每天处理几百万个包裹,如果所有扫码记录都原样保存,仓库再大也会爆。Tempo 的优化策略同样围绕两个词:省钱、加速。
省钱的第一招是 压缩。Tempo 使用 Parquet 列式存储格式,把 Span 按列存放,配合压缩算法,可以大幅缩小数据体积。第二招是 Compactor 合并:把大量小 Block 合并成大 Block,减少对象存储的请求次数和元数据开销。第三招是 采样:如前文所述,在采集端控制进水量。加速方面的核心手段是 缓存:Tempo 为热点 Trace 和最近的索引数据维护多级缓存,避免每次查询都去访问慢速对象存储。
数据压缩后的存储成本可以简单估算为:
假设每天产生 100GB 原始 Span,压缩比 5 倍、三副本存储,最终占用约 60GB,成本立减四成。这就像物流公司把散装小包裹合并进标准大箱,同一辆卡车能装更多货物,单位运输成本自然下降。性能优化的本质,就是在“查得快”和“存得省”之间找平衡。
- Data(原始数据量)所有 Span 的原始体积,随请求量线性增长。
- R_replica(副本因子)为保证可用性,对象存储通常会配置多副本,比如 1 + R = 3 表示三副本。
- r_compress(压缩比)Parquet 加压缩算法通常能把体积压缩到原来的 1/5 甚至 1/10。
实践与排障:从慢请求到快速定位
现在我们把所有知识拼到一起,完成一次真实的排障演练。某天线上监控突然告警:下单接口 P99 延迟从 200ms 飙升到 1.2s。你打开 Grafana,先看指标面板确认异常时段,然后定位到几条典型的慢 Trace,点开瀑布图,发现“支付服务”对应的 Span 耗时占了整条链路的 70%。
进一步下钻,你发现该 Span 内部调用了一个外部 HTTP 接口,而这条调用在 Trace 中显示为“下游超时重试了 3 次”。整个过程不到 5 分钟,这就是成熟追踪平台带来的排障效率。为保障这种效率持续有效,团队应该制定追踪系统的 SLO(服务等级目标):
实践中,团队还会配置“高延迟 Span 告警”:当某个 Span 耗时超过阈值时,自动在 Grafana 中弹出告警并附上对应 Trace 的链接。这样即使不是每个人都会用 TraceQL 写复杂查询,也能顺着告警一键跳转完成定位。复盘时,把高频问题沉淀成最佳实践文档,物流系统才会越用越顺。
- T_down(不可用时长)追踪系统本身发生故障、数据无法查询的累计时间。
- T_period(统计周期)SLO 评估的总时长,比如一个月 30 天换算成分钟数。
- 乘以 100%(百分比表达)将可用性转换为百分比,常见的四个九就是 99.99%。
AI 应用场景
大模型推理链路性能优化
阶段:模型服务部署与监控
解决的问题:一次大模型推理请求往往要经过 API 网关、鉴权、Prompt 预处理、向量检索、模型推理、流式返回等多个环节。传统方式只能看到服务整体延迟,无法判断“慢”到底发生在哪个环节。通过 Tempo 追踪,每个环节的耗时都以 Span 形式呈现,可以精准定位到向量检索或模型推理的瓶颈。
具体案例:某 AI 应用上线后用户反馈响应很慢。工程师在 Grafana 中按 Trace ID 查看一条典型请求,瀑布图显示向量检索阶段耗时 2.3s,占总延迟的 75%。进一步下钻发现是向量数据库的连接池配置过小导致排队,调整后 P95 延迟从 3s 降到了 800ms。
微服务电商大促排障
阶段:云原生应用运维与告警
解决的问题:大促期间订单量暴增,各种偶发超时很难通过日志复现。Tempo 可以保留全量(或采样后)的 Trace 数据,让工程师在问题发生后还能回溯到具体某笔失败请求的完整调用链。
具体案例:用户反馈“提交订单偶尔转圈 10 秒”。通过 Tempo 按 Trace ID 查询异常请求,发现认证服务返回了 503 且触发了 3 次重试。结合日志关联,确认是认证服务的 Redis 连接池打满导致,扩容后问题消失。
跨团队协作的可观测性统一
阶段:可观测性平台建设
解决的问题:多个团队各自维护服务,出现问题互相推诿“不是我的锅”。Tempo + Grafana 提供了统一视图,指标、日志、追踪三合一,团队之间基于同一条 Trace 对话。
具体案例:A 团队抱怨 B 团队接口慢,B 团队说客户端调用方式有问题。在 Grafana 中打开一条完整 Trace,清晰展示 A 服务发出的请求在 B 服务内部确实等待了 1.5s,而等待发生在 B 服务访问数据库的 Span 上,问题归属一目了然。
Python 演示
"""模拟 Tempo 分布式追踪的简化流程:生成链路、写入块、按 Trace ID 查询"""import randomimport time class Span: def __init__(self, trace_id, span_id, parent_id, service, start_ms, dur_ms): self.trace_id = trace_id self.span_id = span_id self.parent_id = parent_id self.service = service self.start_ms = start_ms self.dur_ms = dur_ms class BloomFilter: def __init__(self, size, k): self.size = size self.k = k self.bits = [0] * size def put(self, key): for seed in range(self.k): self.bits[hash((key, seed)) % self.size] = 1 def maybe_contains(self, key): return all(self.bits[hash((key, seed)) % self.size] for seed in range(self.k)) def generate_trace(trace_id, services): spans = [] root = Span(trace_id, trace_id + "-s1", "", services[0], 0, random.randint(20, 80)) spans.append(root) parent = root for i, svc in enumerate(services[1:], start=2): s = Span(trace_id, trace_id + "-s" + str(i), parent.span_id, svc, parent.start_ms + random.randint(0, 10), random.randint(10, 60)) spans.append(s) parent = s return spans class TempoLike: def __init__(self): self.blocks = {} self.bloom = BloomFilter(1024, 3) def ingest(self, spans): trace_id = spans[0].trace_id self.blocks[trace_id] = spans self.bloom.put(trace_id) def query(self, trace_id): if not self.bloom.maybe_contains(trace_id): return [] return self.blocks.get(trace_id, []) def main(): tempo = TempoLike() for i in range(20): tid = "trace-%03d" % i spans = generate_trace(tid, ["frontend", "gateway", "order", "pay"]) tempo.ingest(spans) time.sleep(0.01) tid = "trace-007" result = tempo.query(tid) print("查询 %s 返回 %d 个 Span:" % (tid, len(result))) for s in result: print(" %-10s <- %-10s %-8s %dms+%dms" % (s.span_id, s.parent_id, s.service, s.start_ms, s.dur_ms)) if __name__ == "__main__": main()
class Span:定义追踪数据的最小单元,包含 trace_id、span_id、parent_id 和耗时信息,对应正文中的 Span 数据结构。class BloomFilter:用位数组模拟 Tempo 的 Block 预筛机制,maybe_contains快速回答“可能在里面吗”。generate_trace()模拟一次请求经过多个微服务,自动生成一条带父子关系的调用树。tempo.ingest(spans)模拟 Distributor 和 Ingster 的写入过程,将整条 Trace 存入 Block 并更新索引。tempo.query(trace_id)先通过 Bloom Filter 预筛,再精确查询返回完整链路。
常见误区
误区以为部署好 Tempo 后,服务之间所有调用都会自动出现在追踪面板里,不需要改动任何代码。
正解Tempo 本身只负责存储和查询,不负责采集。你需要通过 OpenTelemetry SDK 在应用里埋点,或者使用自动注入组件(如 Java Agent),数据才会通过 OTLP 上报到 Tempo。这就像物流 App 再强大,也得先有分拣中心扫码上传记录,轨迹才会产生。
为何常见:Tempo 这个词听起来像“完整解决方案”,加上 Grafana 的展示效果很完整,容易让人忽略采集链路的必要性。
误区认为 Bloom Filter 说“不存在”就一定不存在,说“存在”就一定能查到,把预筛结果直接当作精确结果。
正解Bloom Filter 的特性是“可能存在”会有一定误判率,但“一定不存在”是完全可靠的。所以 Tempo 对候选 Block 还要做精确查询,找到的 Trace 才是真实存在的。反过来说,查询结果为空时你可以放心:这条 Trace 一定不在这些 Block 里。
为何常见:日常使用中误判概率极低,几乎感知不到,容易让人误以为它是精确索引。
误区为了“不漏数据”,把采样率设成 100%,觉得既然存储空间够,就不用采样。
正解100% 采样意味着每条请求都要完整存储,数据量随流量线性暴涨,存储成本和查询性能都会恶化。更合理的做法是默认低采样(如 10%),对重点服务或特定错误类型单独提高采样率。物流公司不会对每一件普通包裹都做全程专人跟踪,不值得。
为何常见:开发环境数据量小,100% 采样没有压力,误以为生产环境也可以照搬。
误区觉得有了 Tempo 的瀑布图和 Span 信息,传统日志系统可以下线了,反正每条请求都能追踪。
正解Trace 展示的是“发生了什么、耗时多少”,日志记录的是“具体细节、报错堆栈、业务上下文”。两者需要配合:日志中携带 trace_id,Tempo 查到的 Span 再关联到具体日志行,才能真正还原事故现场。这就像运单轨迹告诉你包裹卡在哪个站点,但“为什么卡住”还得看站点的详细操作记录。
为何常见:第一次看到瀑布图时冲击力很强,容易高估它替代其他可观测性工具的能力。
误区看到 TraceQL 有各种花括号和属性表达式,以为像学一门新编程语言,产生了畏难情绪。
正解TraceQL 的核心语法非常简洁,最常见的就是 { resource.service.name = "foo" } 配合时间范围、属性过滤,入门半小时就能上手。更不用说 Tempo 在 Grafana 中还提供了可视化查询构建器,点选条件就能生成语句。它更像物流 App 的筛选框,而不是一门编程语言。
面试题
Q1. 在分布式追踪中,一次完整的用户请求端到端调用链被称为什么?
- A.Span
- B.Trace← 正确答案
- C.Metric
- D.Block
答案:B。Trace 对应完整请求链路,Span 是其中的单个处理片段。类比物流:Trace 是包裹完整轨迹,Span 是某一次扫码记录。Metric 是指标,Block 是存储单元,都不对。
Q2. 同一个 Trace 中的所有 Span 通过哪个字段关联在一起?
- A.Span ID
- B.Parent ID
- C.Trace ID← 正确答案
- D.Service ID
答案:C。Trace ID 是全局唯一标识,贯穿整条链路的所有 Span,相当于运单号。Span ID 是单个 Span 的自身编号,Parent ID 只表达父子关系,无法把整条链串起来。
Q3. Tempo 中负责接收最新追踪数据并提供热写入能力的是哪个组件?
- A.Distributor
- B.Ingester← 正确答案
- C.Querier
- D.Compactor
答案:B。Ingester 是前台收件员,负责接收并暂存新数据。Distributor 负责分发,Querier 负责查询,Compactor 负责后台压缩合并。注意区分“分发”和“写入”两个环节。
Q4. Tempo 的持久化数据最终主要存放在哪里?
- A.本地磁盘
- B.MySQL 数据库
- C.对象存储← 正确答案
- D.Redis 缓存
答案:C。Tempo 设计为无本地状态依赖,数据以 Block 形式写入 S3、GCS 等对象存储,保证扩展性和低成本。本地磁盘和 Redis 只适合临时缓存,MySQL 不适合海量 Trace 数据。
Q5. Distributor 如何保证同一条 Trace 的 Span 被路由到同一个 Ingester?
- A.随机分配
- B.轮询分配
- C.对 Trace ID 哈希后取余← 正确答案
- D.按服务名分配
答案:C。Tempo 用 hash(trace_id) mod N 做稳定哈希,同一 Trace ID 永远落在同一 Ingester,查询时不必跨节点聚合。随机和轮询会导致同一条 Trace 被拆散到多个节点。
Q6. Bloom Filter 在 Tempo 查询中的作用是什么?
- A.精确查找 Trace 数据
- B.快速排除不含目标的 Block← 正确答案
- C.压缩存储空间
- D.生成 Span ID
答案:B。Bloom Filter 回答“该 Trace ID 可能在这个 Block 中吗”,快速跳过不可能包含目标的 Block。它不保存数据、不压缩数据、不生成 ID,只是预筛工具。
Q7. 在 OpenTelemetry 中,Span 数据上报给 Tempo 使用的是哪个协议?
- A.Prometheus
- B.OTLP← 正确答案
- C.SNMP
- D.JDBC
答案:B。OTLP 是 OpenTelemetry 的标准上报协议,支持 gRPC 和 HTTP 两种传输方式。Prometheus 负责指标抓取,SNMP 是网络设备管理协议,JDBC 是数据库连接接口,均不适用于 Span 上报。
Q8. 以下哪些是 Tempo 的核心后端组件?
- A.Distributor← 正确答案
- B.Ingester← 正确答案
- C.Compactor← 正确答案
- D.Prometheus
答案:ABC。Distributor 负责分发追踪数据,Ingester 负责热数据写入,Compactor 负责合并压缩 Block,三者都是 Tempo 核心组件。Prometheus 是独立的指标监控系统,不属于 Tempo 组件。
Q9. 关于 TraceQL,下列说法正确的有哪些?
- A.支持按服务名过滤← 正确答案
- B.支持按 Span 属性查询← 正确答案
- C.只能通过 Trace ID 查询
- D.支持时间范围过滤← 正确答案
答案:ABD。TraceQL 的核心价值就是不用 Trace ID 也能查,它支持服务名、属性、时长、时间范围等条件。C 选项说“只能按 ID 查”与 TraceQL 的设计初衷完全相反。
Q10. 关于 Tempo 查询性能和存储优化,下面说法正确的有哪些?
- A.缓存可以显著加速热点 Trace 查询← 正确答案
- B.Compactor 把小 Block 合并可降低存储开销← 正确答案
- C.采样率设得越高,查询越快
- D.Parquet 列式存储配合压缩能减小体积← 正确答案
答案:ABD。缓存和压缩分别从加速与省钱两端优化系统,Compactor 合并减少小文件碎片。采样率提高会带来更多数据,反而拖慢查询,并非越高越快,故 C 错误。