全面解析 Grafana Tempo 追踪术语表:从 Trace、Span 到 Spanset、Active Series 与 Cardinality 📅 发布时间:2026/9/17 20:12:46 👁 浏览次数: 全面解析 Grafana Tempo 追踪术语表从 Trace、Span 到 Spanset、Active Series 与 Cardinality【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo本篇文章以 Grafana Tempo 官方文档中的追踪术语表docs/sources/tempo/introduction/glossary.md为骨架系统梳理分布式追踪distributed tracing领域的高频核心概念。无论你是刚接触可观测性的新手还是在用 Tempo 构建大规模追踪后端、排查 TraceQL 查询或评估 metrics-generator 成本的老手读完后你都能准确理解 Trace、Span、Spanset、Intrinsic、各类 attribute、Active Series 与 Cardinality 之间的关联并能结合仓库源码与配置示例把它们用到实际的追踪查询与指标规划中。Trace一次请求的完整生命周期Trace追踪是分布式追踪中最大的逻辑单元它表示一个由端到端请求触发的、跨多个服务与组件传播的完整操作链条。一次用户点击、一次 API 调用、一个后台任务都可能对应一条 Trace。从 Tempo 的存储与查询视角看Trace 具有明显的树形结构有唯一的根root、分支branch与叶子leaf节点任意节点上都可以携带任意的 key/value 数据每一个节点都带有时间戳从而可以还原事件发生的先后顺序。Tempo 官方文档在介绍 TraceQL 时强调Traces are the flow of events throughout your components. They have a tree structure—with a root, branches, and leaves—arbitrary key/value data at any location, and of course timestamps.Trace 是贯穿你各组件的事件流具有树形结构——含根、分支和叶子——可在任意位置携带任意的 key/value 数据当然还有时间戳。在源码层面pkg/traceql/storage.go中的Spanset结构体pkg/traceql/storage.go直观反映了 Trace 在查询引擎中的关键元数据TraceID追踪 ID、RootSpanName根 span 名、RootServiceName根服务名、StartTimeUnixNanos起始时间、DurationNanos总时长以及Spans该 Trace 包含的 span 集合。每条 Trace 都通过全局唯一的Trace ID标识这也是 Tempo 支持按 Trace ID 直接查询如tempo-cli query trace-id的基础。追踪数据通常由 OpenTelemetry 等标准生成通过 OTLP 等协议推送到 TempoTempo 再以 Parquet 列式格式落盘存储。SpanTrace 的基本组成单元Span跨度是 Trace 的最小工作单元代表一次操作operation的时间片例如调用数据库执行 HTTP 请求渲染页面等。一条 Trace 由若干 Span 组成Span 之间通过父子关系构成树形结构。Tempo 的 TraceQL 查询引擎正是以 Span 为基本查询对象——你在 TraceQL 中写{ span.foo bar }本质就是在匹配满足条件的 Span然后 Tempo 返回包含这些 Span 的完整 Trace以 Spanset 形式组织。Root spanTrace 的起点Root span根 span是一条 Trace 中的第一个 span它代表最初的请求或操作。根 span 没有父 span位于整棵 span 树的顶端。整条 Trace 的持续时间、根服务名、根 span 名等聚合信息实际都来源于根 span。这也是 Tempo 支持按trace.rootService、trace.rootSpan等内建字段查询见下文 Intrinsics 小节的原因。Child span被嵌套的子 spanChild span子 span是嵌套在父 span 内部的 span。每个子 span 代表父 span 所表示的更宽泛操作中的一次子操作或下游调用。一个子 span 自身也可以成为其他子 span 的父 span——这正是 Trace 呈现树形结构的由来。例如一次下单请求父 span内部可能嵌套扣减库存子 span而扣减库存内部又可能嵌套调用数据库孙 span。在 OpenTelemetry 规范中子 span 通过parent_span_id与父 span 建立关联在 Tempo 的查询模型中这一关系体现为parentintrinsic见后文用户可以用 TraceQL 表达式如{ parent abc123 }查询指定父 span 的所有子 span。SpansetTraceQL 查询返回的 Span 集合Spansetspan 集是 TraceQL 查询语言中的核心数据结构它是来自同一条 Trace 的一组 span 的集合。Tempo 执行 TraceQL 查询时会从存储中拉取匹配条件的 span并以 Spanset 为单位组织结果——每个 Spanset 对应一条 Trace其中的Spans字段是命中的 span 列表。从源码看Spanset结构体除了Spans []Span之外还携带了该 Trace 的TraceID、RootSpanName、RootServiceName、StartTimeUnixNanos、DurationNanos、ServiceStats服务维度的 span 计数与错误计数统计以及Attributesspanset 级属性并提供了一个ReleaseFn回调用于查询结束后的内存回收pkg/traceql/storage.go。理解 Spanset 的价值在于TraceQL 的 pipeline 运算如{} | count()、{} | select(...)都是作用在 Spanset 上的。Tempo 文档也指出spanset 是 TraceQL 查询与 trace 结构之间关系的桥梁——决定你想查询什么信息以及这些信息落在哪些字段上。Span 的结构属性与事件Span attribute描述操作的元数据键值对Span attributespan 属性是附加在 span 上、用于标注该 span 所跟踪操作信息的 key/value 对。例如一个跟踪加入购物车操作的 span 可能携带用户 ID、商品 ID、购物车 ID 等 span 属性。在 Tempo 中span 属性是 TraceQL 的主要查询对象之一用span.前缀访问如{ span.http.method GET }。需要注意的是TraceQL 允许用.省略前缀例如{ http.method GET }。Resource attribute描述生产实体的键值对Resource attribute资源属性是代表产生 span 的实体信息的 key/value 对例如集群名称、命名空间、Pod 或容器名称。资源属性描述的是这个 span 从哪里来主机/环境维度而非这个 span 做了什么。Tempo 的 Parquet 存储与 TraceQL 查询都将资源属性作为独立维度处理在 TraceQL 中用resource.前缀查询如{ resource.cluster prod }。同时metrics-generator 也可以把资源属性映射为指标标签用于按集群、命名空间等维度聚合 span 指标。Event attributespan 事件上的键值对Event attribute事件属性是附加在 span 事件上的 key/value 对。span 事件span event代表 span 持续期间内的一个时间点例如一次异常抛出、一次缓存未命中、一次重要的状态变更。事件的语义可参考 OpenTelemetry 官方文档中关于 Span Events 的说明。在 Tempo 的 TraceQL 模型中事件可以按名称查询{ event:name exception }事件属性通过event:前缀访问。Link attribute 与 span link跨 span 的因果关联Link attribute链接属性是附加在 span linkspan 链接上的 key/value 对。Span link将某一个 span 与一个或多个在因果上相关的 span 关联起来即使这些 span 并不直接构成父子关系。典型的例子是消息队列场景消费者 span 通过 span link 关联到生产者 span——它们之间的因果跨越了异步边界无法用普通的父子嵌套表达。链接的语义细节可参考 OpenTelemetry 文档中的 Span Links 一节。Tempo 的查询引擎也提供了link.traceID、link.spanID等 intrinsic 支持对链接的查询见下文。Semantic attribute跨语言的标准化命名Semantic attribute语义属性是 OpenTelemetry 规范定义的一套标准化属性命名方案用于统一不同语言、框架和运行时之间的属性名称。例如http.method、http.status_code、db.system等语义约定Semantic Conventions它们保证了从不同技术栈采集到的数据可以用同一种查询语言、同一套规则去检索和聚合。在 Tempo 中正是因为有语义属性的标准化{ span.http.status_code 500 }这样的 TraceQL 查询才能对 Java、Go、Python 等任意语言埋点的服务生效。具体约定可参考 OpenTelemetry 的 Trace Semantic Conventions 文档。IntrinsicsSpan 与 Trace 的内建核心字段Intrinsics内建字段是 span 与 trace 中与身份和生命周期密切相关、由规范定义且始终存在的核心内置字段。根据 Tempo 术语表intrinsic 字段包括名称name、时长duration、状态status和类型kind。在 TraceQL 中intrinsic 是无需span./resource.前缀即可直接访问的保留字段。pkg/traceql/enum_attributes.gopkg/traceql/enum_attributes.go完整定义了 Tempo 支持的 intrinsic 集合包括Intrinsic含义TraceQL 示例namespan 名称{ name GET /users }statusspan 状态ok/error/unset{ status error }kindspan 类型client/server/internal/...{ kind client }durationspan 时长{ duration 100ms }span.idspan 唯一 ID{ span.id ... }parent父 span 的 ID{ parent ... }childCount子 span 数量{ childCount 3 }trace.idtrace ID{ trace.id ... }trace.rootService根服务名{ trace.rootService checkout }trace.rootSpan根 span 名{ trace.rootSpan POST /checkout }trace.duration整条 trace 的时长{ trace.duration 1s }span.startTimespan 开始时间{ span.startTime ... }nestedSet.left/right/parent树嵌套集合编码用于树结构查询link.traceID/link.spanIDspan link 的 trace/span ID{ link.traceID ... }event:name/event:timeSinceStartspan 事件名称 / 距开始时间{ event:name exception }instrumentation.name/instrumentation.version埋点库名称与版本查询特定 SDK 产生的 span可以看到intrinsic 不仅覆盖术语表中提到的 name、duration、status、kind 四个核心字段还扩展到了 trace 级字段trace.id、trace.duration、trace.rootService、trace.rootSpan、树结构字段nestedSet.*、事件字段与链接字段。正是这些内建字段的存在使得 TraceQL 可以不依赖任何自定义属性就能完成查所有错误 span查慢 trace查某个服务的根 span等高频诊断。Active Series指标生成中的活跃时间序列Active series活跃序列指在一段时间内持续接收到新数据点样本的时间序列time series。当你停止向某个时间序列写入新数据点后它很快就将不再被视为活跃序列。Tempo 的 metrics-generator 可以从 trace 生成两类指标能力REDRate/Error/Duration指标面向 span 的速率、错误率与耗时指标服务间依赖图Grafana 中的 Service Graph 功能。这两类能力都依赖一组由 metrics-generator 生成的 span 指标与服务指标。Tempo 摄入的任意 span 都可能产生多个指标序列但这并不意味着每摄入一个 span 就必然创建一个新的活跃序列。活跃序列的计算逻辑活跃序列的数量取决于与指标关联的、由 span 数据派生的标签组合label pair——这与 Prometheus 格式数据的规律一致当某个标签键出现一个新值时活跃序列数量才会增加。Tempo 官方文档以span_kind和status_code两个标签为例做了详细推演见 docs/sources/tempo/metrics-from-traces/metrics-generator/active-series.md单个 span 无分支span_kind恒为SPAN_KIND_INTERNALstatus_code恒为STATUS_CODE_OK只产生1 个活跃序列。即使循环执行 1000 次也只是计数器从 1 累加到 1000活跃序列仍只有 1 个。循环中出现错误status_code出现OK与ERROR两种取值活跃序列变为2 个。调用下游服务且可能失败span_kind增加SPAN_KIND_CLIENT取值与两种status_code组合活跃序列变为4 个。下游服务也产生 span第二个服务的 span 带来SPAN_KIND_SERVER/SPAN_KIND_INTERNAL与两种状态组合最终产生8 个活跃序列。核心结论是决定活跃序列数量的是每个可能出现的 span 状态下标签取值的可变性variability而不是看到的 trace 或 span 的数量。一条 trace 里出现多少次 span都不会改变活跃序列数量。自定义 span 属性对活跃序列的影响metrics-generator 允许将任意的 span 属性映射为指标标签对。在估算活跃序列时还必须考虑被映射为标签的 span 属性有多少种可能取值。例如把http.method加入标签对它有HEAD、GET、POST、PUT、DELETE五种可能取值那么每个 span 指标就额外多出最多 5 个潜在活跃序列——上面的 8 个活跃序列会变成 8 × 5 40 个。因此自定义属性标签是活跃序列规划中最需要警惕的部分。用 dry-run 模式估算活跃序列在全面启用 metrics-generator 之前官方建议先用dry-run干跑模式估算活跃序列规模dry-run 会正常生成指标但不采集、不写入指标存储。具体做法是把 overridemetrics_generator.disable_collection设为true然后正常运行通过查询指标tempo_metrics_generator_registry_active_series得到活跃序列估算值。如果活跃序列已触顶导致该指标不再反映真实需求可改用tempo_metrics_generator_registry_active_series_demand_estimate——它基于 HyperLogLog 算法在限额生效时也能近似估算真实基数。Cardinality标签组合的爆炸之源Cardinality基数指给定指标序列或日志流中 key/value 对如标签与标签值的总组合数以及它们能够产生多少唯一的组合。对时序数据库TSDB而言由于写入按序列组织高基数对摄入性能影响不大但基数越高查询时需要迭代遍历的条目就越多查询性能会受到显著影响。这正是 Tempo 指标链路span metrics、service graph metrics需要关注 cardinality 的根本原因。Trace 采集与指标生成中的基数Tempo 的服务端 metrics 生成在 trace 采集之上增加 Prometheus 格式指标典型包括span 总调用计数total span call countsspan 延迟直方图span latency histogramsspan 总大小计数total span size count。metrics-generator 还会生成描述服务之间边edge与节点node关系的服务图指标。每个指标都可用一组 Prometheus 标签key/value 对查询标签每出现一个新值与该指标关联的活跃序列就会增加——这也就是基数的增长。一个指标生成的活跃序列数量与该指标拥有的标签数量、以及每个标签新增取值的数量直接成正比。在未做自定义配置的 metrics-generator 中自动附加的标签较少span_kind、status_code这类标签的合法取值有限因此活跃序列数量最大的变量来自服务名与 span 名的数量。而一旦配置了自定义 span 属性标签基数就可能急剧膨胀例如把唯一客户 ID100 个客户作为标签活跃序列可能从 25,000 膨胀到 250 万100 倍。基数估算方法对于服务图service graph指标官方给出了可操作的估算公式见 estimate-cardinality.md设系统共有 N 个服务节点任意两个节点之间只要有请求即构成一条hop客户端服务端标签的唯一组合。hop 数量介于#services - 1线性调用链与#services!全互联之间。若#hb为直方图桶数量则各服务图指标的基数约为traces_service_graph_request_total: #hops traces_service_graph_request_failed_total: #hops traces_service_graph_request_server_seconds: #hb * #hops traces_service_graph_request_client_seconds: #hb * #hops traces_service_graph_unpaired_spans_total: #services (绝对最坏情况) traces_service_graph_dropped_spans_total: #services (绝对最坏情况)总基数估算Sum: [([2 * #hb] 2) * #hops] [2 * #services]若配置enable_messaging_system_latency_histogram: true还会额外产生一个直方图。降低基数的实践手段span 名称清理span name sanitizationspan_name标签是高基数的主要贡献者。应用若把动态值如GET /users/123、query-abc-def-ghi写入 span 名每个不同路径或 ID 都会生成独立序列。span_name_sanitization选项基于 DRAIN 算法自动归并相似 span 名把GET /users/123与GET /users/456都映射为GET /users/_从而合并为单条序列参见 reduce-cardinality 文档。谨慎配置自定义属性标签只把确实需要用于指标查询维度的属性映射为标签评估其取值数量对基数的放大效应。用限制limits管理基数包括最大活跃序列限制max active series、基于实体的限制entity-based limiting按唯一标签组合限制以及按标签的基数限制per-label cardinality limiting限制每个标签的不同取值数量。与术语相关的其他关键概念Data source数据源在 Grafana 生态中data source数据源指查询外部系统数据的连接器例如 Prometheus、Loki、CloudWatch 等。Tempo 就是 Grafana 中的追踪数据源用户在 Grafana Explore 中选择 Tempo 数据源后可以使用 TraceQL 查询编辑器/查询构建器query editor/query builder、查看服务图或从日志、指标中跳转drilldown到对应 trace。Tempo 数据源的核心能力是把用户的 trace 查询翻译为对 Tempo 后端的 HTTP 请求。Log 与 Metric与 Trace 并列的观测信号Log日志记录离散事件的文本记录通常带有时间戳与结构化字段。Metric指标聚合的数值度量通常以时间序列形式按固定间隔采样。三者构成可观测性的三大信号logs、metrics、traces。在 Grafana 体系中它们分别由 Loki、Prometheus或 Mimir、Tempo 处理并可以通过 exemplar 等技术互相联动。Exemplar指标与 Trace 之间的桥梁Exemplar示例是一种特殊的指标数据结构它在指标数据点上附加一条指向原始数据的引用。当指标出现异常波动例如 API 延迟飙升时exemplar 允许你从该指标数据点直接跳转到贡献了这次波动的具体 trace从而完成指标发现异常 → trace 定位根因的闭环诊断。在 Tempo 生态中exemplar 的典型用法是metrics-generator 或 Grafana Alloy 在生成 span 指标时把 trace ID 作为 exemplar 附加到直方图等指标上使 Service Graph 与 span 指标可以直接下钻到具体 trace。总结一份速查表术语一句话定义Tempo 中的相关用法Trace一次请求/操作跨组件的完整链条树形结构按 Trace ID 查询TraceQL 以 trace 为返回单位SpanTrace 的基本工作单元一次操作的时间片TraceQL 以 span 为匹配对象Root spanTrace 中第一个、无父 span 的 spantrace.rootService、trace.rootSpan查询Child span嵌套在父 span 内的子操作parentintrinsic 查询父子关系Spanset同一条 Trace 内的一组 span 的集合TraceQL 执行与 pipeline 运算的基本单位Span attributespan 上的元数据键值对span.foo或.foo查询Resource attribute描述生产实体集群/Pod/容器等的键值对resource.foo查询指标标签映射Event attributespan 事件时间点上的键值对event:查询Link attribute / Span link关联因果相关 span 的链接及其属性link.traceID、link.spanID查询Semantic attributeOpenTelemetry 标准化的跨语言属性命名统一的 TraceQL 语义约定Intrinsicsspan/trace 的内建核心字段name、duration、status、kind 等无前缀直接查询的保留字段Active series持续接收新数据点的时间序列tempo_metrics_generator_registry_active_series观测Cardinality标签/标签值的唯一组合总数影响查询性能用 sanitization 与 limits 控制这十四个概念共同构成了理解 Grafana Tempo 数据模型、TraceQL 查询语言与 metrics-generator 指标链路的基础。当你开始编写第一条 TraceQL 查询、规划 span 指标标签或评估服务图基数的成本时这张术语表会是你最常回溯的参考。【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考