.NET结合OpenTelemetry追踪Kafka链路预生产层级断裂问题
.NET中OpenTelemetry追踪Kafka消息链路跨服务关联失效问题
本地测试时,使用OpenTelemetry追踪Kafka消息全生命周期能在Jaeger UI中得到正确的追踪链路,但预生产环境中出现跨服务链路关联失效的问题:
- 服务1的根Activity及其子节点显示正常
- 服务2的根Activity及其子节点显示正常
- 服务2的Activity无法关联到服务1的追踪树中,无法形成统一的层级结构
当前实现方案
- 发送端:提取包含TraceId和SpanId的
Activity.Id,存入消息头后发送消息 - 接收端:消费消息后,通过
ActivitySource创建新Activity,调用SetParentId传入00-traceid-spanid-flags格式的追踪字符串
已确认事项
- 流程各环节均已创建
ActivitySource并调用AddSource - 同一上下文内创建Activity时,未使用
SetParentId,而是在父Activity未释放时创建新Activity - 使用最新版本的.NET、C#、OpenTelemetry及Confluent.Kafka
OpenTelemetry配置
services.AddOpenTelemetry().ConfigureResource(delegate (ResourceBuilder r) { r.AddService(serviceName, environment, serviceVersion); }).WithTracing(delegate (TracerProviderBuilder builder) { builder .SetErrorStatusOnException() .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddAWSInstrumentation() .AddRedisInstrumentation() .AddSqlClientInstrumentation() .AddGrpcClientInstrumentation() .AddOtlpExporter() .AddSource("*") .SetSampler<AlwaysOnSampler>(); }) .WithMetrics(delegate (MeterProviderBuilder builder) { //metrics });
相关伪代码示例
//Activity创建逻辑示例 internal class MyClass { private readonly ActivitySource _activitySource = new(nameof(MyClass)); internal Confluent.Kafka.Message<string,string> SaveTraceIntoMessage() { return new Message<string, string>() { Key = "message.Key", Value = JsonSerializer.Serialize(new { Headers = new [] { new string[] { "traceparent", Activity.Current.Id } } }) }; } //该方法实际属于另一个服务 internal void ReceiveMessage() { var anotherActivitySource = new ActivitySource("Receiver"); var activity = anotherActivitySource.CreateActivity("Receive",ActivityKind.Consumer); //模拟消费逻辑 var consumeMessage = new Message<string, string>(); var pretendIDeserializedTheValueofMessage = consumeMessage.Value; activity.SetParentId(pretendIDeserializedTheValueofMessage); activity.Start(); //业务处理逻辑 activity.Stop(); } internal void ProduceMessage() { using var source = _activitySource.StartActivity("Produce"); Confluent.Kafka.IProducer? producer = GetProducer(); Confluent.Kafka.Message message = SaveTraceIntoMessage(); producer!.Value.Produce(message); } private Confluent.Kafka.IProducer GetProducer() { //返回生产者实例 return null; } }
当前追踪链路效果
服务1与服务2的追踪链路各自独立展示,两个服务的根Activity及下属子节点均能正常显示,但无法建立跨服务的父子关联关系,无法形成统一的追踪层级树。
内容的提问来源于stack exchange,提问作者Fernando Silva
相关产品推荐
相关产品推荐

