- 后端
- 可观测性
- 链路追踪
【免费下载链接】tempo
Grafana Tempo is a high volume, minimal dependency distributed tracing backend.
导读
Grafana Tempo 的分布式追踪后端通过 OTLP gRPC 协议接收遥测数据,其底层网络配置正是由 OpenTelemetry Collector 的configgrpc配置包驱动。本文以vendor/go.opentelemetry.io/collector/config/configgrpc/README.md为骨架,完整解读 gRPC 客户端(Exporter)与服务端(Receiver)的每一项配置参数、Tempo 中的真实落地方式,并结合仓库源码揭示参数背后的实现机制,帮助你精准调优 Tempo 的 OTLP 接入链路。
一、configgrpc 是什么:gRPC 配置的统一抽象
gRPC 本身通过编程方式暴露了种类繁多的设置,而configgrpc将这些设置提炼为可声明式(YAML)配置,供 Collector 生态中的每个 Receiver 或 Exporter 复用。其设计原则是:绝大多数情况下,默认值已经足够,无需调整;只有当遇到连接保活、消息体过大、压缩、负载均衡等特定需求时,才需要显式配置。
在 Tempo 仓库中,该包位于 vendor/go.opentelemetry.io/collector/config/configgrpc,核心实现集中在 configgrpc.go,其中定义了三个核心结构:
ClientConfig(客户端配置):被 Exporter 使用,负责发起 gRPC 连接;ServerConfig(服务端配置):被 Receiver 使用,负责监听和接收 gRPC 请求;- 两类 Keepalive 相关结构:
KeepaliveClientConfig与KeepaliveServerConfig(含ServerParameters、EnforcementPolicy)。
对应地,config.schema.yaml 完整描述了这些配置项的 JSON Schema,是 IDE 校验与配置生成的依据。
二、客户端(Exporter)配置详解
在 OpenTelemetry Collector 体系中,Exporter 使用客户端配置。Tempo 的分布式架构中,各种 Agent、Exporter(如 OTLP Exporter)正是通过这套配置向 Tempo 的 Distributor 推送 Span。
2.1 客户端配置参数总览
| 配置项 | 说明 | 默认值 / 备注 |
|---|---|---|
endpoint | 连接目标地址,语法遵循 gRPC naming 规范 | 支持host:port、dns:///...、unix://...等形式 |
compression | 请求压缩算法 | gzip、snappy、zstd、none |
tls | TLS 客户端配置,参数与服务端一致 | 详见 configtls README |
headers | 附加到每个请求的 name/value 键值对 | 在已存在的请求头缺失时才追加(见 2.4 源码分析) |
keepalive | 客户端保活参数 | 见下文 |
read_buffer_size | gRPC 读缓冲区字节数 | 对应grpc.WithReadBufferSize |
write_buffer_size | gRPC 写缓冲区字节数 | 对应grpc.WithWriteBufferSize |
auth | 出站 RPC 认证配置 | 对应grpc.WithPerRPCCredentials |
middlewares | gRPC 客户端中间件 | 需 host 支持扩展 |
balancer_name | 负载均衡策略名 | v0.103.0 起默认round_robin,之前为pick_first |
wait_for_ready | 是否等待连接就绪后再发送 | 对应 gRPCWaitForReady |
authority | 重写:authority头 | 对应grpc.WithAuthority |
user_agent | 覆盖默认 User-Agent | 为空时由调用方控制 |
2.2 一个完整的最小客户端配置示例
原文档给出了 OTLP gRPC Exporter 的典型配置,直接可复制运行:
exporters: otlp_grpc: endpoint: otelcol2:55690 auth: authenticator: some-authenticator-extension tls: ca_file: ca.pem cert_file: cert.pem key_file: key.pem headers: test1: "value1" "test 2": "value 2"endpoint不需要携带协议前缀,直接写host:port;headers的 key 可含空格,用引号包裹即可;auth.authenticator指向一个已注册的认证扩展。
2.3 关于balancer_name的迁移说明
原文档特别强调了一个易踩的坑:在 Collectorv0.103.0 之前,默认负载均衡策略是pick_first;v0.103.0 起默认改为round_robin。如需恢复旧行为,显式设置:
exporters: otlp_grpc: balancer_name: pick_first在源码层面,configgrpc.go 中定义了DefaultBalancerName = "round_robin",且NewDefaultClientConfig()将BalancerName初始化为该值;当显式配置了balancer_name时,最终通过grpc.WithDefaultServiceConfig将其写入服务配置(见源码 L444-L446)。
2.4 客户端配置的源码级实现机制
从 getGrpcDialOptions 可以看出配置项如何被翻译成真实的 gRPCDialOption:
- 压缩:
Compression.IsCompressed()为真时,通过getGRPCCompressionName解析出 gRPC 注册表中的压缩器名称,并追加grpc.WithDefaultCallOptions(grpc.UseCompressor(cp)); - TLS:先
cc.TLS.LoadTLSConfig(ctx)加载证书;若未配置 TLS,则使用insecure.NewCredentials();当 endpoint 以https://开头时,会自动启用系统默认 TLS 证书(L397-L407); - Keepalive:客户端默认值为
time: 10s、timeout: 10s(见NewDefaultKeepaliveClientConfig),映射为grpc.WithKeepaliveParams; - Headers 注入:
addHeadersIfAbsent的实现表明,只有上下文 outgoing metadata 中尚不存在的 key 才会被追加(L371-L380),且该行为通过一元/流式拦截器同时作用于普通 RPC 与流式 RPC; - 可观测性:无论客户端还是服务端,都会自动挂载
otelgrpc的 StatsHandler,把 gRPC 调用纳入 OpenTelemetry 指标与追踪(L452-L459)。
2.5 关于per_rpc_auth的重要变更
原文档提醒:曾经的per_rpc_auth(允许为每个 RPC 发送凭据)已迁移为独立扩展bearertokenauthextension。它与在headers中配置authorization头有本质区别:
headers中的认证头只在初始连接时发送;per_rpc_auth/ 认证扩展在已建立连接的每一次 RPC上都会携带凭据。
因此涉及逐 RPC 认证的场景,应使用认证扩展而不是静态 headers。
三、服务端(Receiver)配置详解
Receiver 使用服务端配置。在 Tempo 中,Distributor 的 OTLP gRPC Receiver 正是服务端配置的典型消费者。
3.1 服务端配置参数总览
| 配置项 | 说明 | 默认值 / 备注 |
|---|---|---|
transport | 传输层协议 | 默认tcp,可配unix;详见 confignet README |
keepalive | 服务端保活与强制策略 | 见下文 |
max_concurrent_streams | 每个 ServerTransport 的最大并发流数 | 仅对流式 RPC 生效,对应grpc.MaxConcurrentStreams |
max_recv_msg_size_mib | 服务端接受的最大消息体(MiB) | 对应grpc.MaxRecvMsgSize,单位为 MiB |
read_buffer_size | 读缓冲区字节数 | 对应grpc.ReadBufferSize |
write_buffer_size | 写缓冲区字节数 | 对应grpc.WriteBufferSize |
tls | 服务端 TLS 配置 | 默认为 nil(不启用 TLS),见 configtls README |
auth | 接收器认证配置 | 通过服务端拦截器实现 |
include_metadata | 是否将入站连接元数据传播给下游消费者 | 对多租户/认证场景很重要 |
middlewares | gRPC 服务端中间件 | 需 host 支持扩展 |
3.2 Keepalive 服务端配置结构
服务端 keepalive 分为两层,源码中对应KeepaliveServerConfig(configgrpc.go):
server_parameters(对应keepalive.ServerParameters):max_connection_age:连接最大存活时长;max_connection_age_grace:连接超龄后的宽限期;max_connection_idle:空闲连接最大时长;time:服务端发送 keepalive ping 的间隔;timeout:等待 ping 确认的超时。
enforcement_policy(对应keepalive.EnforcementPolicy):min_time:客户端两次 ping 的最小间隔,低于此值会被视为违规;permit_without_stream:是否允许在没有活跃流时发送 ping。
需要注意:这些参数的默认值由 grpc-go 服务端内部统一施加,源码注释(L578-L605)明确指出代码不需要对零值做填充——未配置的字段保持零值直接透传即可。
3.3 服务端配置的源码级实现机制
getGrpcServerOptions 展示了服务端选项的组装顺序:
- TLS:
sc.TLS.Get().LoadTLSConfig(ctx)后通过grpc.Creds挂载; - 消息与并发限制:
MaxRecvMsgSizeMiB * 1024 * 1024换算为字节,MaxConcurrentStreams直接透传; - 拦截器链:按“先 client 信息增强、后 auth”的顺序组合:
enhanceWithClientInformation把对端地址写入client.Info;当include_metadata为真时,还会把入站 metadata(并智能地用:authority兜底hostname)注入上下文(L665-L696);authUnaryServerInterceptor/authStreamServerInterceptor从入站 metadata 提取请求头调用Authenticate,认证失败统一返回codes.Unauthenticated(L698-L736);
- 可观测性:与客户端一致挂载
otelgrpcStatsHandler,并链式注册所有一元/流式拦截器。
四、压缩算法对比与选择
原文档内置了基于 configgrpc_benchmark_test.go 的完整基准数据,测试环境为 AWS m5.large(Intel Xeon Platinum 8259CL @ 2.50GHz),对 log/trace/metric 三类小、中、大负载分别用gzip、snappy、zstd压缩。下表为文档原始数据的整理:
| 请求 | 压缩器 | 原始字节 | 压缩后字节 | 压缩比 | Ns/op | MB/s 压缩 |
|---|---|---|---|---|---|---|
| lg_log_request | gzip | 5150 | 262 | 19.66 | 49231 | 104.61 |
| lg_metric_request | gzip | 6800 | 201 | 33.83 | 51816 | 131.23 |
| lg_trace_request | gzip | 9200 | 270 | 34.07 | 65174 | 141.16 |
| lg_log_request | snappy | 5150 | 475 | 10.84 | 1915 | 2689.30 |
| lg_metric_request | snappy | 6800 | 466 | 14.59 | 2266 | 3000.88 |
| lg_trace_request | snappy | 9200 | 644 | 14.29 | 3281 | 2804.02 |
| lg_log_request | zstd | 5150 | 223 | 23.09 | 17998 | 286.14 |
| lg_metric_request | zstd | 6800 | 144 | 47.22 | 14289 | 475.89 |
| lg_trace_request | zstd | 9200 | 208 | 44.23 | 17160 | 536.13 |
(小负载如sm_*行中,压缩后体积甚至可能超过原始字节——例如sm_log_request在 gzip 下压缩比仅 0.99、snappy 下为 0.90,负的“MB saved / second”意味着小消息压缩反而“亏本”,详见原文档表格。)
结论与选型建议(原文观点):
- 实际压缩比高度依赖数据的信息熵,不同负载差异巨大;
- 压缩速率取决于 CPU 速度与负载大小——小负载无法摊销固定计算开销,压缩速率相对更慢;
gzip是OTLP 服务器唯一强制要求的压缩算法,天然首选:速率不如 snappy,但压缩比更好、性能合理;- 若 Collector 是CPU 瓶颈且 OTLP 服务器支持,可改用
snappy(速度快一个数量级); - 若 Collector CPU 吃紧且网络链路极快,可考虑直接禁用压缩——不压缩本就是默认行为。
在 Tempo 中,compression参数作用于 Distributor OTLP 接入时的消息传输:Tempo 的 receiver/shim.go 直接复用了otlpreceiver工厂与configgrpc配置体系,因此这里关于压缩的选择同样适用于 Tempo 的 OTLP gRPC 接入。
4.1 压缩参数在源码中的映射
configgrpc.go 的getGRPCCompressionName只接受三种注册过的压缩器名:
gzip→google.golang.org/grpc/encoding/gzip(通过 gzip.go 的匿名导入自动注册);snappy→ Collector 内部实现的 snappy;zstd→ Collector 内部实现的 zstd;
其他值一律返回unsupported compression type错误。此外,compressiontype.go 定义了完整的压缩类型枚举(还包含zlib、deflate、x-snappy-framed、lz4等),并区分“是否启用压缩”(none/空字符串视为不压缩)。
五、在 Grafana Tempo 中的真实落地
5.1 Distributor 的 OTLP gRPC 接收器
Tempo 的 Distributor 通过 modules/distributor/receiver/shim.go 将 OpenTelemetry Collector 的 Receiver 嵌入自身进程。从源码可见其关键路径:
- 注册了
otlpreceiver、jaegerreceiver、zipkinreceiver、kafkareceiver四个工厂(L173-L178),其中OTLP Receiver 承载 gRPC/HTTP 双协议; - 将 Tempo 的 YAML 配置转换为 Collector 配置映射后交给
configgrpc解析; - 对 OTLP 接收器,还显式把 HTTP 协议的
IncludeMetadata置为true,以保证认证所需的请求头进入上下文(L263-L269)——这正是 3.3 节include_metadata参数在 Tempo 中的实际用途。
5.2 Tempo 配置中的 gRPC 协议段
单二进制部署的 example/docker-compose/single-binary/tempo.yaml 展示了标准写法:
distributor: receivers: otlp: protocols: grpc: endpoint: "tempo:4317" http: endpoint: "tempo:4318"其中protocols.grpc下所有可配置字段(endpoint、tls、keepalive、max_recv_msg_size_mib、auth等)均由ServerConfig驱动;endpoint对应confignet.AddrConfig,支持tcp(默认)与unix两种传输。默认端口4317是 OTLP gRPC 的行业标准端口,4318为 OTLP HTTP 端口。
5.3 集成测试验证 gRPC 收发路径
receiver/shim_test.go 的TestShim_integration提供了一个可直接参考的端到端模式:
- 用
map[string]interface{}{"otlp": {"protocols": {"grpc": nil}}}启动 Tempo 侧接收器; - 用
otlpexporter配合configgrpc.ClientConfig(Endpoint: "127.0.0.1:4317"、TLS: {Insecure: true})向 Tempo 推送 5 条随机 trace; - 断言
tempo_receiver_accepted_spans指标带transport="grpc"标签。
这说明:endpoint、tls、headers等客户端配置参数在真实链路中逐一生效,并反映在tempo_receiver_accepted_spans、tempo_receiver_refused_spans等监控指标上(对应receiver/shim.go中注册的receiver_enabled_otlp等 usage 统计)。
六、常见调优场景速查
| 目标 | 端 | 配置片段 |
|---|---|---|
| 关闭 TLS(纯内网) | 客户端 | tls: {insecure: true}(见 shim_test 的用法) |
| 限制超大 trace 消息 | 服务端 | max_recv_msg_size_mib: 8(OTLP 默认 4MiB,可按需上调) |
| 快速探测死连接 | 客户端 | keepalive: {time: 10s, timeout: 10s} |
| 防止客户端 ping 过频 | 服务端 | keepalive: {enforcement_policy: {min_time: 10s, permit_without_stream: true}} |
| CPU 受限、服务器支持 snappy | 客户端 | compression: snappy |
| 网络极快、CPU 吃紧 | 客户端 | compression: none(默认即不压缩) |
| 多租户认证 | 服务端 | auth: {authenticator: <扩展>}或依赖include_metadata: true传递租户头 |
| 单连接但多目标 | 客户端 | balancer_name: round_robin(v0.103.0 起默认值) |
结语
configgrpc把 grpc-go 庞大而零散的能力封装成一组声明式配置,是 Tempo OTLP gRPC 接入链路的“神经中枢”。掌握客户端/服务端配置的分工、Keepalive 的层级结构、压缩算法的取舍,以及balancer_name等易变默认值,就能在 Tempo 的高吞吐追踪场景中做到精准调优。更进一步,你可以直接阅读 configgrpc.go 观察配置到grpc.ServerOption/grpc.DialOption的翻译过程,或运行 configgrpc_benchmark_test.go 在自己的 CPU 上重新测量压缩性能,从而用数据指导生产环境的参数决策。
- 后端
- 可观测性
- 链路追踪
【免费下载链接】tempo
Grafana Tempo is a high volume, minimal dependency distributed tracing backend.
相关推荐
Grafana Tempo 中的 OpenTelemetry Collector HTTP 传输配置:confighttp 客户端与服务端参数全解析
Grafana Tempo 中的 OpenTelemetry Collector HTTP 传输配置:confighttp 客户端与服务端参数全解析 Grafa
后端可观测性链路追踪OpenTelemetry Collector gRPC 配置完全指南:configgrpc 客户端/服务端参数、压缩算法与 Keepalive 源码解析
OpenTelemetry Collector gRPC 配置完全指南:configgrpc 客户端/服务端参数、压缩算法与 Keepalive 源码解析 本篇
可观测性后端运维观测OpenTelemetry Collector confighttp 配置详解:HTTP 客户端与服务端全参数解析
OpenTelemetry Collector confighttp 配置详解:HTTP 客户端与服务端全参数解析 在 OpenTelemetry Collec
可观测性后端运维观测
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考