Grafana Tempo 内嵌 OTel Collector 组件:exporterhelper 内部遥测指标与 Feature Gate 完全指南
【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo
本文以 Grafana Tempo 仓库内 vendored 的go.opentelemetry.io/collector/exporter/exporterhelper模块为对象,系统梳理其内部遥测(Internal Telemetry)的全部 17 个指标与 1 个 Feature Gate。Tempo 以库的形式内嵌 OpenTelemetry Collector 生态组件(见 go.mod 中exporter/exporterhelper v0.153.0、exporter/otlpexporter v0.153.0直接依赖,以及 modules/distributor/receiver/shim.go 中通过otelcol构建 Collector 配置启动 receiver 的实现),因此 exporterhelper 的遥测语义直接适用于 Tempo 及任何集成 OTel Collector exporter 的系统。读完本文,你将掌握每个指标的含义、数据类型、稳定级别、采集实现原理,以及发送队列、重试、超时等配置与指标之间的联动关系。
exporterhelper 是什么:一类被所有 exporter 复用的基础设施
exporterhelper是 OpenTelemetry Collector 中为所有 exporter 提供通用能力的辅助包。正如其在 README.md 中所述,该包为 exporter 提供可复用的实现,当前包括**排队(queuing)、批处理(batching)、超时(timeouts)与重试(retries)**四类能力。
在 Grafana Tempo 中,Collector 生态并非以独立进程方式运行,而是被直接以 Go 库的形式编译进二进制。例如 modules/distributor/receiver/shim.go 在创建 OTLP 等 receiver 时,构造了一份包含receivers、exporters(此处使用nopexporter 以避免报错)与service.pipelines的 Collector 配置,再通过otelcol.NewConfigProvider解析并启动。这意味着:
- Tempo 的 trace 接收端就是 Collector 生态的 receiver/exporter 组件;
- 任何被启用的 exporter(如 OTLP exporter)在发送数据时,其排队、批处理、超时、重试行为都由
exporterhelper统一驱动; - 与之配套的内部遥测指标,全部由
exporterhelper的观测层(obsReportSender)发出,命名统一以otelcol_exporter_为前缀。
内部遥测指标全景:17 个指标的分类视图
documentation.md定义的所有指标均由mdatagen从 metadata.yaml 自动生成,可在 internal/metadata/generated_telemetry.go 中看到对应的TelemetryBuilder字段声明。按功能可划分为六组:
| 分组 | 指标 | 度量类型 | 语义 |
|---|---|---|---|
| 入队失败 | otelcol_exporter_enqueue_failed_{log_records,metric_points,profile_samples,spans} | Sum | 未能进入发送队列而被丢弃的数据量 |
| 在途请求 | otelcol_exporter_in_flight_requests | Sum(UpDown) | 当前正在导出(含重试退避)的请求数 |
| 批量发送 | otelcol_exporter_queue_batch_send_size、otelcol_exporter_queue_batch_send_size_bytes | Histogram | 每次发出的批次规模(单位数 / 字节数) |
| 队列状态 | otelcol_exporter_queue_capacity、otelcol_exporter_queue_size | Gauge | 重试队列的固定容量与当前积压 |
| 发送失败 | otelcol_exporter_send_failed_{log_records,metric_points,profile_samples,spans} | Sum | 发往目标端失败的记录数 |
| 发送成功 | otelcol_exporter_sent_{log_records,metric_points,profile_samples,spans} | Sum | 成功送达目标端的记录数 |
四类信号(traces / metrics / logs / profiles)各自的计数指标共享同一套模板,仅 unit 与稳定性等级不同。下面逐组详解,完整继承原始定义。
入队失败类:enqueue_failed_*
数据在进入发送队列之前就被拒绝时(例如队列已满、持久化队列底层存储不可写),不会进入 exporter 的重试逻辑,而是直接丢弃,并由这组指标统计。Tempo 场景下,这类指标是判断入口流量是否被背压丢数据的第一信号。
otelcol_exporter_enqueue_failed_log_records:未能加入发送队列的日志记录数。
| Unit | Metric Type | Value Type | Monotonic | Stability |
|---|---|---|---|---|
| {record} | Sum | Int | true | Alpha |
otelcol_exporter_enqueue_failed_metric_points:未能加入发送队列的指标数据点数。
| Unit | Metric Type | Value Type | Monotonic | Stability |
|---|---|---|---|---|
| {datapoint} | Sum | Int | true | Alpha |
otelcol_exporter_enqueue_failed_profile_samples:未能加入发送队列的 profile 样本数(该指标仍处于 Development 阶段)。
| Unit | Metric Type | Value Type | Monotonic | Stability |
|---|---|---|---|---|
| {sample} | Sum | Int | true | Development |
otelcol_exporter_enqueue_failed_spans:未能加入发送队列的 span 数。
| Unit | Metric Type | Value Type | Monotonic | Stability |
|---|---|---|---|---|
| {span} | Sum | Int | true | Alpha |
在途请求:otelcol_exporter_in_flight_requests
当前处于“在途”状态的导出请求数,包括重试退避期间等待中的请求。它是 UpDownCounter(Monotonic 为 false),会随请求开始与结束上下波动。该指标用于评估 exporter 的并发压力:数值长期接近上限,说明目标端处理不过来。
| Unit | Metric Type | Value Type | Monotonic | Stability |
|---|---|---|---|---|
| {request} | Sum | Int | false | Development |
批量发送直方图:queue_batch_send_size 与 _bytes
otelcol_exporter_queue_batch_send_size统计每次实际发出的批次包含的单位数(span / 指标点 / 日志记录数),可用于验证批处理配置(min_size、max_size)是否生效。
| Unit | Metric Type | Value Type | Stability |
|---|---|---|---|
| {unit} | Histogram | Int | Development |
otelcol_exporter_queue_batch_send_size_bytes统计发出的批次序列化后的字节数,仅在 detailed 级别的遥测下可用。两个直方图的 bucket 边界定义在 metadata.yaml 中,前者覆盖 10 到 100000,后者覆盖 10 到 6000。
| Unit | Metric Type | Value Type | Stability |
|---|---|---|---|
| By | Histogram | Int | Development |
队列状态:queue_capacity 与 queue_size
otelcol_exporter_queue_capacity:重试队列的固定容量,单位是批次(batch)。它由sending_queue.queue_size配置决定(默认 1000 批),是稳定的 Gauge。
| Unit | Metric Type | Value Type | Stability |
|---|---|---|---|
| {batch} | Gauge | Int | Alpha |
otelcol_exporter_queue_size:重试队列当前积压的批次数量,同样是 Gauge。它反映了瞬时背压水平,queue_size / queue_capacity逼近 1 时意味着即将出现入队失败(即enqueue_failed_*开始增长)。
| Unit | Metric Type | Value Type | Stability |
|---|---|---|---|
| {batch} | Gauge | Int | Alpha |
发送失败类:send_failed_*
记录发往目标端的失败尝试中涉及的数据量。在 detailed 遥测级别下,该组指标带有两个属性:error.type(遵循语义约定)与error.permanent(标识错误是否永久性、不可重试)。error.permanent常量定义于 internal/obs_report_sender.go(ErrorPermanentKey = "error.permanent")。永久性错误(如数据格式非法)不会被重试逻辑挽回,可结合该属性对失败原因分类治理。
otelcol_exporter_send_failed_log_records:发往目标端失败的日志记录数。
| Unit | Metric Type | Value Type | Monotonic | Stability |
|---|---|---|---|---|
| {record} | Sum | Int | true | Alpha |
otelcol_exporter_send_failed_metric_points:发往目标端失败的指标数据点数。
| Unit | Metric Type | Value Type | Monotonic | Stability |
|---|---|---|---|---|
| {datapoint} | Sum | Int | true | Alpha |
otelcol_exporter_send_failed_profile_samples:发往目标端失败的 profile 样本数(Development 阶段)。
| Unit | Metric Type | Value Type | Monotonic | Stability |
|---|---|---|---|---|
| {sample} | Sum | Int | true | Development |
otelcol_exporter_send_failed_spans:发往目标端失败的 span 数。
| Unit | Metric Type | Value Type | Monotonic | Stability |
|---|---|---|---|---|
| {span} | Sum | Int | true | Alpha |
发送成功类:sent_*
与失败类一一对应,统计成功送达目标端的记录数。成功率 = sent / (sent + send_failed),两个指标均为单调递增的 Counter,可在 Prometheus 中用rate()观察趋势。
otelcol_exporter_sent_log_records:成功发往目标端的日志记录数。
| Unit | Metric Type | Value Type | Monotonic | Stability |
|---|---|---|---|---|
| {record} | Sum | Int | true | Alpha |
otelcol_exporter_sent_metric_points:成功发往目标端的指标数据点数。
| Unit | Metric Type | Value Type | Monotonic | Stability |
|---|---|---|---|---|
| {datapoint} | Sum | Int | true | Alpha |
otelcol_exporter_sent_profile_samples:成功发往目标端的 profile 样本数(Development 阶段)。
| Unit | Metric Type | Value Type | Monotonic | Stability |
|---|---|---|---|---|
| {sample} | Sum | Int | true | Development |
otelcol_exporter_sent_spans:成功发往目标端的 span 数。
| Unit | Metric Type | Value Type | Monotonic | Stability |
|---|---|---|---|---|
| {span} | Sum | Int | true | Alpha |
指标背后的实现:观测链路与 sender 链
理解这些指标的发出位置,有助于在实际排障时定位问题出自哪一层。
sender 链的构建顺序
在 internal/base_exporter.go 的NewBaseExporter中,发送链路按以下顺序包装(数据从内向外依次经过):
- Consumer Sender:真正的导出逻辑(调用目标 exporter);
- Timeout Sender:仅当
timeout非 0 时启用,控制单次导出尝试的时间上限; - Retry Sender:仅当
retry_on_failure.enabled时启用,负责指数退避重试; - ObsReport Sender:总是启用,负责采集发送成功 / 失败 / 在途指标;
- Queue Sender:仅当配置了
sending_queue时启用,负责排队与批处理,并把数据交给firstSender。
因此指标采集(ObsReport)位于重试与队列之间:入队失败(enqueue_failed)发生在进入 Queue Sender 之前,不会到达重试逻辑;发送失败 / 成功(send_failed / sent)与在途(in_flight)则由 ObsReport 在重试之外统计。
观测实现细节
obsReportSender(见 internal/obs_report_sender.go)为每个 exporter 与信号组合创建 span,命名格式为exporter/<exporter_id>/<signal>,并附带exporter、data_type属性。TelemetryBuilder(generated_telemetry.go)通过NewTelemetryBuilder从组件级TelemetrySettings的MeterProvider创建所有计数器、直方图与可观测 Gauge;两个队列 Gauge(queue_capacity/queue_size)通过RegisterExporterQueueCapacityCallback/RegisterExporterQueueSizeCallback注册异步回调采集。
Feature Gate:exporter.PersistRequestContext
documentation.md的 Feature Gates 部分定义了一个与持久化队列相关的开关:
| Feature Gate | Stage | Description | From Version | To Version |
|---|---|---|---|---|
exporter.PersistRequestContext | stable | 控制是否将 context 与请求一起存储进持久化队列 | v0.128.0 | v0.154.0 |
该开关的元数据同时登记在 metadata.yaml 中,对应 OpenTelemetry Collector PR #13188。含义要点:
- 启用后,请求的 context(含 client metadata 与 span context)会随数据一并持久化,重启后恢复导出的数据仍能保留这些上下文信息;
- 但需要注意,Auth 扩展写入 context 的鉴权信息不会被持久化(详见 README.md),因此持久化队列恢复出的数据不携带认证上下文;
- 该开关从 v0.128.0 引入、v0.154.0 后行为固化(
stable阶段,当前仓库 vendored 的版本为 v0.153.0,正处于该开关的有效窗口内)。更完整的 Feature Gate 机制说明见 Collector 的featuregate包文档。
配置与指标联动:从 README 继承的完整参数表
exporterhelper的 README 给出了与上述指标直接相关的全部配置项,理解它们才能正确解读指标。以下参数均可在使用 Collector exporter 的配置(或 Tempo 内嵌 collector 组件的构造代码)中设置。
失败重试 retry_on_failure
| 参数 | 默认值 | 说明 |
|---|---|---|
enabled | true | 是否在导出失败后重试 |
initial_interval | 5s | 首次失败后的等待时间;enabled=false时忽略 |
max_interval | 30s | 退避间隔上限;enabled=false时忽略 |
max_elapsed_time | 300s | 发送单个批次累计花费的最大时间;设为 0 表示永不停止重试;enabled=false时忽略 |
multiplier | 1.5 | 每次重试间隔的放大倍数;enabled=false时忽略 |
对应的默认值与校验逻辑位于 vendor/go.opentelemetry.io/collector/config/configretry/backoff.go:默认间隔 5s、间隔上限 30s、最大累计时间 5 分钟;校验规则要求max_elapsed_time不小于initial_interval与max_interval。重试采用指数退避(cenkalti/backoff),并带随机化因子(randomization_factor,默认在 [0,1] 内)。这些重试行为与otelcol_exporter_in_flight_requests(退避期间仍算在途)以及send_failed_*的error.permanent属性直接相关。
发送队列 sending_queue
| 参数 | 默认值 | 说明 |
|---|---|---|
enabled | true | 是否启用发送队列 |
num_consumers | 10 | 从队列取批次的消费者数量;enabled=false时忽略 |
wait_for_result | false | 入队请求是否阻塞等待处理结果 |
block_on_overflow | false | 队列满时是否阻塞等待空位;为 false 则立即拒绝数据 |
sizer | requests | 队列与批处理的计量方式:requests(按请求/批次数,性能最佳)、items(按最小数据单元数)、bytes(按序列化字节数,性能最差) |
queue_size | 1000 | 队列可容纳的最大批次数量,单位由sizer决定 |
batch | 禁用 | 批处理配置,见下 |
失败行为:数据无法进入发送队列时通常被丢弃——包括队列达到容量上限,或持久化队列底层存储无法写入(磁盘空间不足、I/O 错误)。启用block_on_overflow后调用方可能等待空位并在超时前成功入队。被拒数据不会进入重试逻辑,由otelcol_exporter_enqueue_failed_*统计——这正是解读该组指标的关键前提(见 README.md)。
批量设置 batch(默认关闭,显式写batch: {}可启用默认值):
| 参数 | 默认值 | 说明 |
|---|---|---|
flush_timeout | 200ms | 批次达到该时间即发出,必须非 0 |
min_size | 8192 | 批次的单位数下限;若batch::sizer与sending_queue::sizer相同,则应不大于queue_size |
max_size | 0 | 批次单位数上限,支持拆分超大批次;0 表示无上限 |
sizer | 继承父级 | items或bytes;未设置时取父结构值,父级也未设置则默认items |
partition | 空 | 批次分区:metadata_keys为client.Metadata键列表,按键值组合分派到不同 batcher;空值/未设置视为独立分区;键不区分大小写,重复项触发校验错误 |
批次的最终规模反映在otelcol_exporter_queue_batch_send_size与_bytes直方图中,可用其分位数验证min_size/max_size设置的实际效果。
超时 timeout
| 参数 | 默认值 | 说明 |
|---|---|---|
timeout | 5s | 每次向目标端发送数据的单次尝试等待时间 |
initial_interval、max_interval、max_elapsed_time与timeout均接受 Go duration 字符串(如5s、1m),合法时间单位包括ns、us(或µs)、ms、s、m、h。
持久化队列(Persistent Queue)
启用持久化队列只需设置sending_queue.storage指向某个 storage 扩展(如 filestorage),此时不再使用内存队列,磁盘上缓存的批次上限同样由queue_size控制(默认 1000 批)。Collector 进程被杀死时队列中残留的批次会在重启后继续导出。README 给出了完整示例配置:
receivers: otlp: protocols: grpc: exporters: otlp_grpc: endpoint: <ENDPOINT> sending_queue: storage: file_storage/otc extensions: file_storage/otc: directory: /var/lib/storage/otc timeout: 10s service: extensions: [file_storage] pipelines: metrics: receivers: [otlp] exporters: [otlp] logs: receivers: [otlp] exporters: [otlp] traces: receivers: [otlp] exporters: [otlp]对应的队列状态(queue_capacity/queue_size)与批次大小直方图在持久化模式下同样有效,可用于监控磁盘队列积压与消费速度。
运维实践:用这些指标定位导出链路问题
综合上述定义,可形成以下排障路径(以 trace 信号为例):
otelcol_exporter_sent_spans的rate()与otelcol_exporter_enqueue_failed_spans对比:如果入队失败持续增长而发送成功平稳,问题在队列容量或持久化存储(如磁盘满),而不是目标端;otelcol_exporter_queue_size / otelcol_exporter_queue_capacity逼近 1:队列接近打满,优先扩容queue_size或增加num_consumers,并检查block_on_overflow设置以避免静默丢弃;otelcol_exporter_in_flight_requests长期处于高位:目标端吞吐不足,重试退避中的请求也计入该值,需检查retry_on_failure的退避参数与目标端健康;otelcol_exporter_send_failed_spans增长:按error.permanent属性区分永久性失败与可重试失败,永久性失败(如数据格式错误)应在上游治理,可重试失败则可调整initial_interval/max_interval/max_elapsed_time;- 批次直方图形态异常:
otelcol_exporter_queue_batch_send_size若始终贴近min_size且flush_timeout频繁触发,说明流量稀疏,可下调min_size以降低延迟。
上述全部指标的定义源文件为 documentation.md,指标元数据(含直方图 bucket 边界与稳定性声明)可在 metadata.yaml 中查阅,生成代码位于 internal/metadata/generated_telemetry.go。需要留意的是,各指标的 Stability 差异(Alpha / Development)意味着其 API 与语义在 Collector 演进中可能调整,升级版本时应回归核对告警规则。
【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考