针对基于 RPC 调用的核心应用,OpenTelemetry Agent 的配置确实有特殊之处。以下是关键注意点:
RPC 调用的特殊配置
1. RPC 协议识别
OpenTelemetry Agent 需要正确识别 RPC 协议类型,常见协议:
| RPC 框架 | Agent Instrumentation | 配置项 |
|---|---|---|
| gRPC | grpc-1.6 |
otel.instrumentation.grpc.enabled=true |
| Dubbo | dubbo-2.7 |
otel.instrumentation.dubbo.enabled=true |
| Thrift | thrift |
otel.instrumentation.thrift.enabled=true |
| Motan | motan |
otel.instrumentation.motan.enabled=true |
| RSocket | rsocket |
otel.instrumentation.rsocket.enabled=true |
在你的配置中需要明确启用:
# otel-agent.properties
# RPC 框架(根据实际情况选择)
otel.instrumentation.grpc.enabled=true
otel.instrumentation.dubbo.enabled=true
otel.instrumentation.grpc.experimental-span-attributes=true
# 如果用了 Spring Cloud Stream / RabbitMQ / Kafka 做 RPC
otel.instrumentation.spring-rabbit.enabled=true
otel.instrumentation.kafka.enabled=true
2. 跨服务上下文传播
RPC 调用需要正确的 Propagation Format,这是最常见的坑:
# 传播格式(根据 RPC 框架选择)
otel.propagators=tracecontext,baggage,b3
# 如果 RPC 框架使用自定义 Header,需要配置
otel.propagators=b3 # Zipkin B3 格式
otel.propagators=w3c # W3C TraceContext(推荐)
常见场景:
- Dubbo:使用
attachment传递 context,Agent 会自动处理 - gRPC:使用
metadata传递,需要otel.instrumentation.grpc.enabled=true - 自定义 RPC:可能需要手动传播 context
3. Span 命名规范
RPC 调用的 Span 命名很重要,影响 APM 平台的展示:
# 启用 RPC 语义约定
otel.instrumentation.grpc.experimental-span-attributes=true
# 自定义 Span 名称(如果需要)
# Agent 会自动生成类似:POST /service/method
4. 性能优化配置
RPC 调用通常是高频操作,需要注意
# 采样率(生产环境建议降低)
otel.traces.sampler=parentbased_traceidratio
otel.traces.sampler.arg=0.1 # 10% 采样率
# 批量导出配置(减少网络开销)
otel.bsp.schedule.delay=5000 # 5秒刷新一次
otel.bsp.max.queue.size=2048 # 最大队列
otel.bsp.max.export.batch.size=512 # 批量大小
# 如果 RPC 调用很频繁,增加队列
otel.bsp.max.queue.size=4096
5. 错误处理
RPC 调用的异常需要正确记录:
# 记录异常信息到 Span
otel.instrumentation.experimental.span-exception-event-enabled=true
# 如果 RPC 框架使用特定异常,确保被捕获
# 例如 Dubbo 的 RpcException
完整的 RPC 应用配置示例
# otel-rpc-agent.properties
# ===== 基础配置 =====
otel.service.name=core-rpc-service
otel.resource.attributes=deployment.environment=prod,service.version=2.1.0
# ===== RPC 框架配置 =====
# gRPC
otel.instrumentation.grpc.enabled=true
otel.instrumentation.grpc.experimental-span-attributes=true
# Dubbo(如果使用)
otel.instrumentation.dubbo.enabled=true
otel.instrumentation.dubbo.consumer.enabled=true
otel.instrumentation.dubbo.provider.enabled=true
# ===== 上下文传播 =====
otel.propagators=tracecontext,baggage,b3
# ===== 采样配置 =====
otel.traces.sampler=parentbased_traceidratio
otel.traces.sampler.arg=0.1
# ===== 导出配置 =====
otel.traces.exporter=otlp
otel.exporter.otlp.endpoint=http://192.168.17.100:9013
otel.exporter.otlp.protocol=grpc
otel.exporter.otlp.timeout=10s
# 批量导出优化
otel.bsp.schedule.delay=5000
otel.bsp.max.queue.size=4096
otel.bsp.max.export.batch.size=512
# ===== 排除配置 =====
# 排除健康检查等高频调用
otel.instrumentation.grpc.exclude-patterns=/grpc.health.v1.Health/*
# ===== 其他 =====
otel.metrics.exporter=none
otel.logs.exporter=none
特殊场景处理
场景 1:RPC 调用跨异步边界
如果你的 RPC 调用在异步线程中:
// 需要手动传播 Context
Span span = tracer.spanBuilder("async-rpc-call").startSpan();
try (Scope scope = span.makeCurrent()) {
// RPC 调用
CompletableFuture.runAsync(() -> {
// 在异步线程中,Context 会自动传播(Agent 会处理)
rpcClient.call();
});
} finally {
span.end();
}
场景 2:自定义 RPC 协议
如果使用了自研 RPC 框架:
// 需要在代码中手动埋点
@WithSpan("custom-rpc-call")
public Response rpcCall(Request req) {
// 手动添加属性
Span.current().setAttribute("rpc.system", "custom");
Span.current().setAttribute("rpc.service", req.getService());
Span.current().setAttribute("rpc.method", req.getMethod());
return rpcClient.invoke(req);
}
场景 3:RPC 熔断/限流
如果使用了熔断器(如 Resilience4j):
otel.instrumentation.resilience4j.enabled=true
# 或者 Hystrix(如果还在用)
otel.instrumentation.hystrix.enabled=true
验证清单
启动后检查:
- Span 命名是否正确:
- 应该看到类似
POST /com.example.UserService/getUser - 而不是简单的
HTTP POST
- 应该看到类似
- 跨服务链路是否完整:
Gateway → Service A (RPC) → Service B (RPC) → Database - 上下文传播是否正常:
# 查看日志中的 traceId 是否一致 curl http://gateway/api/test # 查看各服务日志的 traceId - 性能影响是否可接受:
# 对比接入 Agent 前后的 RPC 延迟 # 通常在 1-3ms 以内是可接受的
常见问题
Q: RPC 调用的 TraceId 不一致?
A: 检查 otel.propagators 配置,确保客户端和服务端使用相同的传播格式。
Q: RPC Span 数量太多?
A: 降低采样率 otel.traces.sampler.arg=0.1,或排除特定方法。
Q: RPC 调用异常没有被记录?
A: 启用 otel.instrumentation.experimental.span-exception-event-enabled=true。