Grafana Tempo 可观测性指南:四大支柱、Trace 关联机制与落地实践
【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo
可观测性(Observability)由指标(Metrics)、日志(Logs)、追踪(Traces)与性能剖析(Profiles)四大支柱构成,本指南以 Grafana Tempo 文档库中的《Traces and telemetry》为骨架,系统讲解四大信号各自的定位与相互关系,并深入 Tempo 仓库源码与配套文档,给出从指标跳转 Trace、从日志跳转 Trace 及反向关联的完整实践方案。读完本文,你将掌握四大支柱的协同原理,理解 Tempo 如何在自我追踪、指标生成(Exemplar)与自动日志记录等场景中打通信号间的关联,并能据此搭建自己的可观测性链路。
可观测性的四大支柱:各司其职的信号
Metrics、logs、traces 和 profiles 构成了可观测性的四大支柱。它们各自从不同维度回答"系统发生了什么"这一问题,而将这四类信号相互关联,才能形成对应用与基础设施的整体视图。这也是理解 Tempo 这类分布式追踪后端在整个可观测性体系中所处位置的前提。
指标(Metrics):量化系统状态的基石
指标从宏观层面描述系统的状态,是告警体系的基础,原因在于:
- 指标是数值型数据,可以与已知阈值直接比较;
- 告警规则可以在后台持续运行,当数值超出预期范围时触发通知;
- 指标异常通常是第一信号,是问题发现(Discovery)的起点。
一句话概括:指标告诉你"有事情正在发生"(Metrics indicate that something is happening)。例如请求速率突然飙升、错误率越过阈值,都是通过指标最先感知的。
日志(Logs):单进程活动的审计轨迹
日志来自单一进程,以原子事件的形式记录服务内部正在发生的事,提供丰富的上下文信息:
- 指标是定量的(numeric)、结构化的;日志是定性的(textual)、非结构化或半结构化的;
- 日志细节丰富,但代价是显著更高的数据量(higher data volumes);
- 日志告诉你"应用正在发生什么"(what's happening to your application)。
在排障时,日志能回答"具体报了什么错、参数是什么",但缺少跨组件的交互上下文。
追踪(Traces):数据通路上的分步地图
追踪在可观测性图景上更进一步,它告诉你数据通路中每一步发生了什么,相当于一张"哪里出了问题"的地图:
- 一个 trace 以图形化方式展示数据流中每个步骤耗时多少,例如一次 HTTP 请求、一次数据库查询、一次第三方服务调用分别耗时多少;
- 它能展示请求从哪里发起、在哪里结束,以及系统如何响应;
- 这种能力帮助你在从未预料到的地方定位问题区域并评估影响——没有追踪能力,这些瓶颈往往难以发现。
关于 trace 与 span 的基础模型,可参考仓库中的 Trace structure 文档 与 Glossary:trace 由若干 span 组成,span 是 trace 中的工作单元,带起始时间、持续时长与操作名,并可通过 parent 引用形成 span 树。
性能剖析(Profiles):定位可优化代码行
剖析帮助理解应用如何利用 CPU 时间、内存等计算资源,进而定位具体的代码行或函数进行优化,提升性能与效率。它是四大支柱中最"微观"的一类信号。
为什么需要 Trace:单靠指标与日志无法根治复杂问题
- 指标自身不足以定位根因:它只能告诉你"出问题了",无法告诉你"为什么";
- 日志虽信息量大,但缺乏复杂环境中各组件之间交互与依赖的上下文;
- 每一类信号在根因定位上都有独特优势,要最大化可观测性战略的价值,必须把它们关联起来(correlate them)。
Trace 的独特能力在于展示服务之间的关系:
- 识别你的服务**上游(upstream)**有哪些服务——这有助于理解"当你的服务出问题时,哪些服务会受负面影响";
- 识别你的服务**下游(downstream)**有哪些服务——由于你的应用依赖这些下游服务,它们的故障很可能正是你服务报错或延迟升高的根源;
- 例如,你可以直接看到正在失败的数据库以及所有受影响的边缘端点。
换句话说,trace 是在微服务架构中把"指标异常"翻译成"服务依赖关系"的关键桥梁。
从指标到 Trace:Exemplar 关联机制
指标与 trace 的关联核心是Exemplar(示例)。借助 exemplar,你可以从某个指标数据点直接跳到与之关联的 trace,例如从"某个百分位延迟异常"直接打开对应的一次完整请求追踪。
在 Tempo 中,Exemplar 有两种典型来源:
1. metrics-generator 自动生成 Exemplar
Tempo 的 metrics-generator 组件在处理传入 span 时,会基于 span 计算 RED 指标(Rate 请求速率、Error 错误率、Duration 持续时长直方图),并自动生成 exemplar,从而支持"指标 → trace"的一键跳转。该能力在 Metrics from traces 文档中有明确说明。
从源码看,service graphs 处理器在观测直方图时会携带 trace ID:在 servicegraphs.go 中,处理器通过e.TraceID()取得当前 span 的 trace ID,并在ObserveBorrowed(..., traceID, ...)时将 trace ID 写入指标观测,这正是 exemplar 携带 trace 标识的实现路径。
在配置层面,你可以通过metrics_generator.processor.span_metrics.trace_id_label_name指定生成指标中保存 trace ID 的标签名(默认值为traceID),详见 configuration/_index.md;该标签名必须是合法的 Prometheus 标签名,校验逻辑位于 validation/fields.go。
2. TraceQL 指标查询中的 Exemplar
Tempo 的 TraceQL 指标(metrics queries)为所有 range 查询提供 exemplar 能力:你可以在 query-frontend 中通过参数query_frontend.metrics.max_exemplars配置(默认100,设置为0表示禁用,见 configuration/_index.md),也可以在查询中直接加 hint:
{ span:name = "GET /:endpoint" } | quantile_over_time(duration, .99) by (span.http.target) with (exemplars=true)这样,查询返回的时间序列上就会带上具体 trace 的引用,点开数据点即可跳转到完整 trace。详细说明见 TraceQL metrics 文档。
从 Trace 到日志、从日志到 Trace:双向跳转
除指标外,trace 与日志之间同样需要双向关联:
- 从 trace 到日志:查看某一次请求的 trace 时,能看到沿途服务产生的日志条目,从而补充 trace 之外的异常细节;
- 从日志到 trace:在日志中发现可疑的 trace ID 后,直接跳转到该 trace 查看完整调用链。
在 Tempo 生态中,实现日志 ↔ trace 关联最典型的手段是Grafana Alloy 的自动日志记录(Automatic logging)。其原理与配置在 automatic-logging.md 中有完整说明:
- 自动日志记录通过
otelcol.connector.spanlogs连接器从 trace span 生成日志行,每个 span/root/process 生成一条logfmt风格的日志,包含svc(服务名)、span(span 名)、dur(span 时长,纳秒)、tid(trace ID)、status(显式状态)等默认键; - 该连接器不会转发原始 trace,因此必须同时把 trace 发送给 trace 后端(如 Tempo),避免丢数据;
- 生成的日志可写入 Loki,配合 Grafana 的 Loki 数据源Derived fields配置(匹配
tid字段并指向 Tempo 数据源),即可在日志界面点击跳转到对应 trace。
例如下面的 Alloy 配置将 root span 记录为日志并发送到 OTLP 端点,同时把 trace 转发给同一端点:
otelcol.receiver.otlp "default" { grpc {} http {} output { traces = [ otelcol.connector.spanlogs.default.input, otelcol.exporter.otlp.default.input, ] } } otelcol.connector.spanlogs "default" { roots = true output { logs = [otelcol.exporter.otlp.default.input] } } otelcol.exporter.otlp "default" { client { endpoint = env("OTLP_ENDPOINT") } }生成的 root span 日志行示例:
span="HTTP GET" dur=150200000ns http.method=GET http.target=/api/v1/query svc=my-service tid=7bba9f33312b3dbb8b2c2c62bb7abe2d也可以直接用 LogQL 查询自动日志,例如筛选慢请求:
{traces="root"} | logfmt | dur > 2s and svc="my-service"值得说明的是,Tempo 原生也提供等价的 TraceQL 搜索(无需 Loki),例如{ resource.service.name = "my-service" && span:duration > 2s }即可实现同样的慢请求发现。
让 Tempo 自己成为观测对象:自追踪与元监控
理解了四大支柱之后,一个自然的延伸问题是:追踪系统本身如何被观测?Tempo 仓库提供了两个层面的实践:
Tempo 自追踪(Self-tracing)
Tempo 使用 OpenTelemetry SDK 对自身进行插桩,可以通过环境变量导出自身产生的 trace(详见 self-tracing.md)。其底层初始化逻辑在 pkg/tracing/tracing.go 中实现:
InstallOTelOrJaegerFromEnv从OTel 或 Jaeger 环境变量初始化全局 tracer,两者都未配置时为空操作(no-op);- 服务名默认为
tempo-<target>(<target>为-target标志的值),可用OTEL_SERVICE_NAME或JAEGER_SERVICE_NAME覆盖,且JAEGER_SERVICE_NAME优先(见 tracing.go); - 该函数由 cmd/tempo/main.go 在启动早期调用,并传入
config.SpanProfiling以决定是否启用 span profiling。
关键环境变量包括:
| 类别 | 环境变量 | 说明 |
|---|---|---|
| OTel | OTEL_EXPORTER_OTLP_ENDPOINT | OTLP 端点 URL,例如http://tempo:4318 |
| OTel | OTEL_EXPORTER_OTLP_TRACES_ENDPOINT | 仅 traces 的端点,覆盖上述端点 |
| OTel | OTEL_TRACES_EXPORTER | traces 导出器,默认otlp,设为none时仅传播上下文不导出 |
| OTel | OTEL_TRACES_SAMPLER/OTEL_TRACES_SAMPLER_ARG | 采样器与参数,支持always_on、always_off、traceidratio、parentbased_*以及jaeger_remote等 |
| OTel | OTEL_PROPAGATORS | 上下文传播器,默认tracecontext、baggage、jaeger |
| OTel | OTEL_RESOURCE_ATTRIBUTES | 附加的自定义 resource 属性 |
| Jaeger | JAEGER_AGENT_HOST/JAEGER_ENDPOINT | Jaeger agent 主机 / collector 端点 |
| Jaeger | JAEGER_SAMPLER_TYPE/JAEGER_SAMPLER_PARAM | 采样类型(const、probabilistic、remote)与参数 |
| Jaeger | JAEGER_AGENT_PORT | Jaeger agent 端口,默认6831 |
| Jaeger | JAEGER_TAGS | 以key1=value1,key2=value2格式附加 resource 属性 |
仓库中的 tracing_test.go 对采样行为做了直接验证:例如always_on采样所有 trace、always_off不采样、traceidratio按比例采样,以及jaeger_remote/parentbased_jaeger_remote对initialSamplingRate的解析与非法参数(缺少endpoint)的报错校验。
此外还支持强制采样单次请求:在请求上设置Jaeger-Debug-IdHTTP 头,Tempo 将无视采样配置强制采样该请求,并把头值作为jaeger-debug-idspan 属性写入(需激活jaeger传播器)。Span profiling 则可通过配置span_profiling: true或--span-profiling标志开启,为 span 附加 pprof goroutine 标签与pyroscope.profile.id属性,将 trace span 与运行期间采集的 profile 关联起来——这正对应四大支柱中trace 与 profile 的关联。
Tempo 元监控(Metamonitoring)
若想完整观测 Tempo 自身的指标与日志,可使用 set-up-monitoring.md 与共享文档 metamonitoring.md 描述的方案:通过 Grafana Kubernetes Helm chart(k8s-monitoring)配置 Grafana Alloy 抓取 Tempo 的prom-metrics端口指标与 Pod 日志,分别 remote-write 到 Prometheus/Mimir 与 Loki。其values.yml核心片段如下:
integrations: tempo: instances: - name: "traces" # instance 标签名 namespaces: - traces # 搜索 Tempo 实例的命名空间 metrics: enabled: true portName: prom-metrics logs: enabled: true labelSelectors: app.kubernetes.io/name: tempo destinations: - name: "metrics" type: prometheus url: "<url>" # 例如 https://<prometheus host>/api/prom/push - name: "logs" type: loki url: "<url>" # 例如 https://<loki host>/loki/api/v1/push之后可从仓库的operations/tempo-mixin-compiled目录导入 8 个监控 Dashboard(如tempo-operational.json),并使用mimirtool上传rules.yaml与alerts.yaml(分别对应 recording rules 与告警规则),实现"指标 → 告警 → 日志 → trace"的完整闭环监控。Mixin 源文件位于 operations/tempo-mixin,编译产物位于 operations/tempo-mixin-compiled。
总结:让四类信号协同工作
可观测性的价值不在于单个信号,而在于关联:
| 信号 | 回答的问题 | 与其他信号的关联方式 |
|---|---|---|
| Metrics | 是否有事情发生? | Exemplar 跳转到 trace |
| Logs | 具体发生了什么? | trace ID(tid)跳转到 trace,反之 trace 可下钻日志 |
| Traces | 在哪一步、哪个服务出了问题? | 关联上下游服务、关联指标与日志 |
| Profiles | 哪些代码需要优化? | 通过 span profiling 与 trace span 关联 |
Tempo 在整个体系中扮演 trace 的存储、检索与关联枢纽:借助 metrics-generator 与 TraceQL 指标生成携带 exemplar 的指标、借助自动日志记录打通日志侧入口、借助自追踪让自身也被四类信号观测。在实际部署中,建议结合 部署模式文档 与 架构文档 规划组件形态,再按本文所述逐步配置信号关联,最终形成"指标发现问题 → trace 定位链路 → 日志补充细节 → profile 优化性能"的完整排障工作流。
【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考