Grafana Tempo 应用洞察实践:用 Span Metrics 识别性能瓶颈并建立 SLO
2026/9/18 9:28:01 网站建设 项目流程

Grafana Tempo 应用洞察实践:用 Span Metrics 识别性能瓶颈并建立 SLO

【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo

Traces 为应用性能提供了直接的可观测窗口,而 Tempo 的 metrics-generator 组件能够把这些 Trace 数据转化为开箱即用的 RED(Rate、Error、Duration)指标,让你在不需要额外埋点的情况下监控服务延迟、错误率与吞吐量。本篇技术指南以虚构电商公司 Handy Site Corp 的实战场景为主线,完整讲解如何基于 Tempo 生成的 span metrics 定义合理的 SLO(服务级别目标)、利用 exemplar 从指标一键跳转到代表性 Trace,并借助 Grafana SLO 应用建立基于 SLI 的告警体系。读完本文,你将掌握traces_spanmetrics_latency等核心指标的标签结构与查询方式、metrics-generator 的完整配置项(自定义维度、维度映射、过滤策略、采样率补偿等),以及源码级别的实现原理,能够直接在自己的 Tempo 部署中落地一套可量化的服务质量监控方案。

从 Trace 到应用洞察:为什么需要用 Trace 驱动性能分析

Traces 是一扇观察应用性能的窗口,它记录了单个请求在一次分布式调用中经历的每一个环节。借助 Trace 数据,你能够:

  • 定位系统中的瓶颈,找到拖慢整体响应时间的具体服务或操作;
  • 发现潜在的性能优化点,降低延迟与响应时间,从而提升应用吞吐量;
  • 在故障发生时快速完成问题分诊(triage),判断问题出在哪个服务、哪条调用链上。

但原始 Trace 数据量巨大且以请求为粒度,很难直接回答"这段时间整体延迟如何"这样的聚合问题。Tempo 提供的解法是:在服务端用metrics-generator组件直接从 Trace 生成指标,让"洞察"变成可持续观测的、可告警的、可量化评估的数据。

场景引入:Meet Handy Site Corp

为了说明完整思路,官方文档引入了一个虚构公司 Handy Site Corp:一家运营电商应用的网站公司,其系统由用户认证(authentication)、商品目录(catalog)、订单管理(order management)、支付处理(payment processing)等多个服务组成。

这类微服务系统正是 Trace 数据的典型来源:一次结账请求会跨越多个服务,任何一个环节变慢都会直接拖累用户体验。因此,Handy Site 的工程师选择从 Trace 出发,围绕结账流程的延迟建立可度量的服务质量体系。

定义现实可行的 SLO

Handy Site 的工程师首先为结账流程建立围绕延迟的服务级别目标(SLO)。一个正确的 SLO 应当是基于正常运营时期的历史数据推算出来的现实目标,而不是拍脑袋定下的理想值——只有贴近真实水平的 SLO 才具有监控和告警的意义。

确定 SLO 之后,团队会配置告警,用于在"有风险无法达成该目标"时及时发出信号。SLO 告警的价值在于:它只在 SLI 的当前取值表明团队面临失守风险时才触发,从而避免传统阈值告警带来的告警噪音。

使用 Span Metrics 定义 SLI

Handy Site 在评估后,决定使用span metrics(跨度指标)作为服务级别指标(SLI)来衡量 SLO 的达成情况。SLI 是 SLO 的量化载体,它把"用户是否获得良好体验"翻译成可测量、可追踪的指标值。

Tempo 使用 metrics-generator 组件从 Trace 生成指标。这些指标基于传入 Trace 中的 span 创建,开箱即用地反映应用流程与整体概貌,其中包括 RED 指标——Rate(请求速率)、Error(错误率)和 Duration(持续时间/延迟)。这意味着即使你的系统没有预先接入传统的指标采集体系,只要实现了分布式追踪,就能从追踪管道中获得现成的应用级指标

Span Metrics:metrics-generator 的核心产出物

要理解 SLI 的构造,首先需要完整了解 span metrics 生成了哪些指标。根据官方文档与源码,span metrics 处理器(span metrics processor)会为每一种"维度组合"计算 span 的总数与持续时间,维度可以是服务名、操作名、span 类型、状态码,以及 span 上的任意属性(attribute)。这些指标的定义在源码中有明确对应,见 spanmetrics.go:

指标名类型标签描述
traces_spanmetrics_latencyHistogram维度标签span 的持续时间(延迟分布)
traces_spanmetrics_calls_totalCounter维度标签span 的总调用次数
traces_spanmetrics_size_totalCounter维度标签摄入 span 的总大小(字节)

从源码可以看到这三个子处理器(subprocessor)的默认开关状态:LatencyCountSize默认全部启用(见 config.go),因此默认部署下三个指标都会生成。如果你只需要其中部分指标,可以在 overrides 配置中通过子处理器单独控制,例如只保留延迟直方图与调用次数计数器:

overrides: defaults: metrics_generator: processors: - span-metrics-latency - span-metrics-count # span-metrics-size 被省略,即关闭 size 指标

默认标签:一个指标上的内建维度

metrics-generator 会为生成的每个指标附加一组默认标签(intrinsic dimensions),包括servicespan_namespan_kindstatus_code。这些标签的含义如下:

  • service— 产生该 span 的服务名称;
  • span_name— span 的唯一名称(即操作名);
  • span_kind— span 的类型,取值为五种之一:
    • SPAN_KIND_SERVER— 该 span 由来自其他服务的调用生成;
    • SPAN_KIND_CLIENT— 该 span 发起了对另一个服务的调用;
    • SPAN_KIND_INTERNAL— 该 span 在其所在服务内部完成,无外部交互;
    • SPAN_KIND_PRODUCER— 该 span 创建了推送到总线或消息代理的数据;
    • SPAN_KIND_CONSUMER— 该 span 消费了总线或消息系统上的数据;
  • status_code— span 的结果,取值为三种之一:
    • STATUS_CODE_UNSET— 结果未设置/未知;
    • STATUS_CODE_OK— span 操作成功完成;
    • STATUS_CODE_ERROR— span 操作以错误结束。

源码中的aggregateMetricsForSpan函数展示了这些标签如何从每个 span 上提取并加入指标序列(见 spanmetrics.go),而spanKindString/statusCodeString两个函数则在热路径上把 OTLP 枚举转换为可读的标签字符串。

除此之外还有三个可选标签,默认不开启:

  • status_message(可选)— 描述status_code原因的消息,需要显式开启;
  • job— 命名空间与服务的组合名称,仅在metrics_generator.processor.span_metrics.enable_target_info: true时添加;
  • instance— 实例 ID,仅在enable_target_info: trueenable_instance_label: true时添加。

Exemplar:从指标一键跳回 Trace

span metrics 还让 exemplar 的使用变得异常简单。Exemplar 是聚合到某个指标观测中的一个详细样本:它包含观测值本身,以及可选的时间戳和任意 Trace ID——通常正是用于关联到某条 Trace 的 ID。

由于 Trace 与指标在 metrics-generator 内部共存,exemplar 可以自动附加到生成的指标上。这带来两个非常实用的工作流:

  • 从展示"延迟随时间聚合"的指标图,快速跳转到代表低延迟、中延迟或高延迟请求的某条具体 Trace;
  • 从展示"错误率随时间变化"的指标图,快速跳转到出错的某条具体 Trace。

在源码层面,exemplar 由直方图实现承载:histogram.go中每个 bucket 都维护了 exemplar 与对应观测值(见 histogram.go),而 span metrics 处理器在观测延迟时会传入 span 的TraceId(见 spanmetrics.go),从而把"哪个请求贡献了这个观测值"记录下来。这就是从指标图点击 exemplar 直接进入 Trace 详情的底层机制。

监控延迟:用 traces_spanmetrics_latency 构造 SLI

回到 Handy Site 的场景。团队最关心结账服务(checkout service)处理的请求延迟,并设定目标:一个月内 99.5% 的请求应在 2 秒内完成

为了构造能够追踪该目标的 SLI,他们使用traces_spanmetrics_latency指标,并配合适当的标签选择器,例如service name = checkoutservice。由于 metrics-generator 默认已为指标添加span_kindstatus_code等标签,查询可以直接基于service标签过滤出结账服务的数据,再按延迟分布评估达标比例。

如果团队想进一步按端点(endpoint)软件版本分别统计结账服务延迟,可以修改 Tempo metrics-generator 的配置,把这些自定义维度(custom dimensions)作为标签加入 span metrics。

添加自定义维度

自定义维度通过dimensions配置项添加,其值取自 span 或 resource 上的属性。完整的配置结构位于metrics_generator.processor.span_metrics之下,例如:

metrics_generator: processor: span_metrics: dimensions: - http.method - http.route # 按端点拆分延迟 - deployment.environment

需要留意的细节:

  • 当某个配置的维度与默认标签冲突时(例如配置了status_code),该维度生成的标签会被加上双下划线前缀,变成__status_code
  • 在 Prometheus 标签名转换后允许重复维度,以便兼容不同埋点库的不同命名习惯。例如可以同时配置deployment.environmentdeployment_environment(两者都会转换为deployment_environment),发生冲突时最后配置的值生效
  • 维度越多,生成指标的基数(cardinality)越高,需要在洞察力与资源消耗之间做权衡。

重命名与组合维度:dimension_mappings

如果希望把属性重命名为自定义标签名,或把多个属性合并成一个复合标签,可以使用dimension_mappings配置。它的source_labels必须填写原始 span/resource 属性名(带点号,如deployment.environment),而不是清洗后的 Prometheus 标签名;name字段中点和下划线都会被统一转换为下划线。

例如,把deployment.environment重命名为更短的env标签:

dimension_mappings: - name: env source_labels: ["deployment.environment"]

再例如,把service.nameservice.namespaceservice.version组合成单个标签service_instancejoin参数指定连接符:

dimension_mappings: - name: service_instance source_labels: ["service.name", "service.namespace", "service.version"] join: "/"

当 span 携带service.name = "abc"service.namespace = "def"service.version = "ghi"时,生成的指标标签即为service_instance="abc/def/ghi"。这与源码中aggregateMetricsForSpanDimensionMappings的拼接逻辑一致(见 spanmetrics.go)。

控制默认内建维度以降低基数

如果某些默认标签不需要,可以通过intrinsic_dimensions关闭它们,从而降低指标基数:

metrics_generator: processor: span_metrics: intrinsic_dimensions: service: true span_name: true span_kind: false # 关闭 span_kind 标签 status_code: true status_message: false # 默认即关闭

处理采样后的 Trace:span multiplier

如果你在 Trace 进入 Tempo 之前使用了基于比例的采样器,指标计数会因此失真。metrics-generator 提供两种补偿方案:

方案一:自定义 span 属性。在采样器中把采样率写入 span 属性,例如X-SampleRatio,然后在配置中指定:

metrics_generator: processor: span_metrics: span_multiplier_key: "X-SampleRatio"

方案二:W3C tracestate 阈值。如果采样器使用 OpenTelemetry 的th(threshold)子键把采样概率记录在 W3C tracestate 头中,可以开启自动提取:

metrics_generator: processor: span_metrics: enable_tracestate_span_multiplier: true

当 tracestate 缺失或无效时,配置会回退到基于属性的方案。源码中usesSpanMultiplierGetSpanMultiplier的处理逻辑见 spanmetrics.go。

用过滤策略裁剪指标

在部分场景下你可能只想为特定流量生成指标,这可以通过filter_policies实现。支持include(逻辑 AND)、include_any(逻辑 OR,命中即包含)与exclude(命中即排除)三类策略,match_type支持strict(严格比较)与regex(正则匹配),过滤属性支持booldoubleintstring类型,以及namestatuskind等内建 span 属性。

例如只保留 kind 为 server 的 span:

metrics_generator: processor: span_metrics: filter_policies: - include: match_type: strict attributes: - key: kind value: SPAN_KIND_SERVER

非内建属性需要按 TraceQL 的语法指定作用域,例如resource.location。更复杂的组合可以实现"包含 EU 生产环境的所有 span、但额外放行 auth-service 的内部 span、同时剔除 dev 环境"这类灵活策略:

metrics_generator: processor: span_metrics: filter_policies: # 只处理来自 EU 生产环境的 span - include: match_type: regex attributes: - key: resource.location value: eu-.* # 例外规则:允许 auth-service 的 INTERNAL span - include_any: match_type: strict attributes: - key: kind value: SPAN_KIND_INTERNAL - key: resource.service.name value: auth-service # 丢弃所有开发环境 tier 的 span - exclude: match_type: regex attributes: - key: resource.tier value: dev-.*

完整的指标定义、标签说明与配置示例,可进一步阅读仓库中的官方文档 span-metrics-metrics-generator.md 与 metrics-generator 总览。

在 Grafana 中建立 SLO 与基于风险的告警

一切就绪后,Handy Site 打开 Grafana 的SLO 应用,按照设置流程为结账服务围绕traces_spanmetrics_latency指标建立 SLI。要点如下:

  • SLI 定义:使用traces_spanmetrics_latency直方图,配合service="checkoutservice"等标签选择器,量化"2 秒内完成请求"的比例;
  • SLO 目标:把 99.5% 的月度达标率作为服务级别目标;
  • 告警信号:基于 SLO 的告警只在 SLI 取值表明团队有失守风险时触发,因此既能及时暴露直接影响用户体验的服务质量劣化,又不会产生传统固定阈值告警那样的噪音告警。

这种告警模式在可观测性实践中被称为"基于风险的告警"(SLO-based alerting):告警不再是"某个指标超过阈值",而是"照当前趋势发展,我们可能无法兑现对用户的承诺"。它天然把告警与业务影响绑定在一起,也让排障优先级变得清晰——当支付服务延迟上升导致 SLO 失守风险增加时,团队立刻知道该处理哪条链路。

源码级原理:Span Metrics 处理器的内部机制

最后,从源码层面梳理 span metrics 处理器的完整工作链路,帮助你理解上述每个配置项的实际作用点:

  1. 入口PushSpans接收 OTLP 格式的 span 批次,交由aggregateMetrics处理(见 spanmetrics.go)。在 Tempo 3.0 微服务部署中,metrics-generator 改为从 Kafka 消费 Trace 数据;单二进制部署中 distributor 仍在进程内调用PushSpans

  2. 资源级预处理:每个 resource 批次只提取一次service.name(即 job 名)与实例 ID,避免在单个 span 的热路径上重复计算。

  3. 过滤:每个 span 先经过filter_policies判定,不满足策略的 span 被跳过并计入filteredSpansCounter

  4. 标签构建aggregateMetricsForSpan依次加入内建维度(service、span_name、span_kind、status_code、可选的 status_message)、自定义dimensionsdimension_mappings生成的标签,以及可选的job/instance标签。

  5. 指标更新:根据启用的子处理器分别更新计数器与直方图。延迟计算基于 span 的StartTimeUnixNanoEndTimeUnixNano,负延迟按 0 处理(见 spanmetrics.go);直方图观测时携带 span 的TraceId以生成 exemplar。

  6. 基数控制:指标基数由"维度组合的数量"决定。默认的直方图桶为指数桶(起始 0.002 秒、步长 2 倍、共 14 个桶),在启用自定义维度前应通过 cardinality 文档 评估基数影响。

  7. 输出:metrics-generator 内部运行一个 Prometheus Agent,通过可配置的remote_write端点把指标推送到 Prometheus 或兼容后端(如 Grafana Mimir);写入间隔由metrics_generator.registry.collection_interval控制。多租户场景下会透传X-Scope-OrgID请求头,可通过remote_write_add_org_id_header: false关闭。

小结

本文以 Handy Site Corp 的电商场景为线索,完整演示了"用 Trace 驱动应用洞察"的落地路径:先基于历史数据定义现实可行的 SLO,再以 metrics-generator 生成的 span metrics 作为 SLI,通过traces_spanmetrics_latency等指标配合标签选择器量化延迟表现,借助 exemplar 在指标与 Trace 之间自由穿梭,最后在 Grafana SLO 应用中建立基于风险的告警。同时,通过dimensionsdimension_mappingsfilter_policiesspan_multiplier_key等配置,你可以把这套方案精确裁剪到自己的服务拓扑、版本管理与采样策略之上。相关配置的完整参考与更多高级选项,可继续阅读仓库文档 metrics-generator 配置、架构与处理器总览 以及源码 spanmetrics.go 与 config.go。

【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询