微服务的追踪怎么实现?有哪些开源组件可以用?

在微服务架构中,分布式追踪(Distributed Tracing) 是一个关键的工具,用于监控和调试复杂的服务调用链。分布式追踪能够帮助开发者理解请求在各个服务之间的流动路径,识别性能瓶颈和故障点,从而提高系统的可靠性和性能。以下是实现微服务追踪的方法以及一些常用的开源组件。

实现分布式追踪的方法

  1. 上下文传播:
    • 在服务之间的请求中传播追踪上下文信息,如追踪ID、跨度ID、采样决策等。
    • 常用的上下文传播协议包括B3、W3C TraceContext等。
  2. 追踪数据收集:
    • 收集每个服务中的追踪数据,如请求开始时间、结束时间、调用的服务、调用的资源等。
    • 使用追踪库或框架来自动收集这些数据。
  3. 数据存储:
    • 将追踪数据存储到集中式的存储系统中,如时序数据库、消息队列等。
    • 常用的存储系统包括Elasticsearch、InfluxDB、Cassandra等。
  4. 数据可视化:
    • 使用可视化工具来展示追踪数据,帮助开发者分析请求路径和性能问题。
    • 常用的可视化工具包括Jaeger、Zipkin、Prometheus + Grafana等。

常用的开源组件

  1. Jaeger
  • 特点:

    • 由Uber开发的开源分布式追踪系统。
    • 支持多种语言和框架。
    • 提供强大的可视化界面。
    • 支持B3、W3C TraceContext等上下文传播协议。
  • 组件:

    • Jaeger Agent:用于收集追踪数据。
    • Jaeger Collector:用于接收并存储追踪数据。
    • Jaeger Query:用于查询和展示追踪数据。
    • Jaeger UI:提供可视化界面。
  • 集成示例:
    在.NET应用中使用Jaeger,可以通过Jaeger.Client库来实现。

      using Jaeger;
      using Jaeger.Samplers;
      using Jaeger.Reporters;
      using Jaeger.Senders.Thrift.Http;
      using OpenTracing;
      using OpenTracing.Util;
    
      public class TracingConfig
      {
      	public static ITracer InitTracer(string serviceName)
      	{
      		var sampler = new ConstSampler(true);
      		var reporter = new RemoteReporter.Builder()
      			.WithSender(new HttpSender("http://localhost:14268/api/traces", new Configuration.HttpSenderConfiguration(), new List<string>()))
      			.Build();
    
      		var tracer = new Tracer.Builder(serviceName)
      			.WithSampler(sampler)
      			.WithReporter(reporter)
      			.Build();
    
      		GlobalTracer.Register(tracer);
      		return tracer;
      	}
      }
    
      public class OrderService
      {
      	private readonly ITracer _tracer;
    
      	public OrderService(ITracer tracer)
      	{
      		_tracer = tracer;
      	}
    
      	public void CreateOrder(OrderCreationDto orderDto)
      	{
      		using (var scope = _tracer.BuildSpan("CreateOrder").StartActive())
      		{
      			var span = scope.Span;
      			span.Log("Creating order");
    
      			// 应用层逻辑:数据验证
      			if (orderDto.Items == null || orderDto.Items.Count == 0)
      			{
      				throw new ArgumentException("Order items are required.");
      			}
    
      			// 创建订单本地事务
      			var order = new Order
      			{
      				UserId = orderDto.UserId,
      				Items = orderDto.Items.Select(itemDto => new OrderItem
      				{
      					ProductId = itemDto.ProductId,
      					Quantity = itemDto.Quantity
      				}).ToList(),
      				TotalAmount = orderDto.Items.Sum(itemDto => itemDto.Price * itemDto.Quantity)
      			};
    
      			// 记录其他操作
      			span.Log("Order created");
    
      			// 调用其他服务
      			var paymentService = new PaymentService(_tracer);
      			paymentService.ProcessPayment(order.Id, order.TotalAmount);
      		}
      	}
      }
    
  1. Zipkin
  • 特点:

    • 由Twitter开发的开源分布式追踪系统。
    • 支持多种语言和框架。
    • 提供强大的可视化界面。
    • 支持B3、W3C TraceContext等上下文传播协议。
  • 组件:

    • Zipkin Collector:用于接收并存储追踪数据。
    • Zipkin Storage:支持多种存储后端,如Elasticsearch、Cassandra等。
    • Zipkin Query:用于查询和展示追踪数据。
    • Zipkin UI:提供可视化界面。
  • 集成示例:
    在.NET应用中使用Zipkin,可以通过Zipkin.Tracing库来实现。

      using Zipkin.Tracing;
      using Zipkin.Tracing.Builder;
      using Zipkin.Tracing.Core;
      using Zipkin.Tracing.Handlers;
      using Zipkin.Tracing.Http;
      using OpenTracing.Util;
    
      public class TracingConfig
      {
      	public static ITracer InitTracer(string serviceName)
      	{
      		var tracer = new TracerBuilder("my-service")
      			.WithSampler(new AlwaysSampler())
      			.WithReporter(new HttpReporter("http://localhost:9411/api/v2/spans"))
      			.Build();
    
      		GlobalTracer.Register(tracer);
      		return tracer;
      	}
      }
    
      public class OrderService
      {
      	private readonly ITracer _tracer;
    
      	public OrderService(ITracer tracer)
      	{
      		_tracer = tracer;
      	}
    
      	public void CreateOrder(OrderCreationDto orderDto)
      	{
      		using (var scope = _tracer.BuildSpan("CreateOrder").StartActive())
      		{
      			var span = scope.Span;
      			span.Log("Creating order");
    
      			// 应用层逻辑:数据验证
      			if (orderDto.Items == null || orderDto.Items.Count == 0)
      			{
      				throw new ArgumentException("Order items are required.");
      			}
    
      			// 创建订单本地事务
      			var order = new Order
      			{
      				UserId = orderDto.UserId,
      				Items = orderDto.Items.Select(itemDto => new OrderItem
      				{
      					ProductId = itemDto.ProductId,
      					Quantity = itemDto.Quantity
      				}).ToList(),
      				TotalAmount = orderDto.Items.Sum(itemDto => itemDto.Price * itemDto.Quantity)
      			};
    
      			// 记录其他操作
      			span.Log("Order created");
    
      			// 调用其他服务
      			var paymentService = new PaymentService(_tracer);
      			paymentService.ProcessPayment(order.Id, order.TotalAmount);
      		}
      	}
      }
    
  1. OpenTelemetry
  • 特点:

    • 由CNCF(Cloud Native Computing Foundation)维护的开源项目。
    • 提供统一的API和SDK来收集和导出追踪数据。
    • 支持多种语言和框架。
    • 可以与多种后端集成,如Jaeger、Zipkin、Prometheus等。
  • 组件:

    • SDKs:提供用于收集追踪数据的SDK。
    • Exporters:支持多种后端,如Jaeger、Zipkin、Prometheus等。
    • Collectors:用于接收和存储追踪数据。
    • UI:通过其他工具(如Jaeger UI、Zipkin UI)进行可视化。
  • 集成示例:
    在.NET应用中使用OpenTelemetry,可以通过OpenTelemetry库来实现。

      using OpenTelemetry;
      using OpenTelemetry.Trace;
      using OpenTelemetry.Exporter.Jaeger;
      using OpenTelemetry.Instrumentation.HttpClient;
      using System.Net.Http;
    
      public class TracingConfig
      {
      	public static TracerProvider InitTracer(string serviceName)
      	{
      		return Sdk.CreateTracerProviderBuilder()
      			.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(serviceName))
      			.AddHttpClientInstrumentation()
      			.AddSource(serviceName)
      			.AddJaegerExporter(o =>
      			{
      				o.AgentHost = "localhost";
      				o.AgentPort = 6831;
      			})
      			.Build();
      	}
      }
    
      public class OrderService
      {
      	private readonly TracerProvider _tracerProvider;
      	private readonly HttpClient _httpClient;
    
      	public OrderService(TracerProvider tracerProvider, HttpClient httpClient)
      	{
      		_tracerProvider = tracerProvider;
      		_httpClient = httpClient;
      	}
    
      	public void CreateOrder(OrderCreationDto orderDto)
      	{
      		using (var activity = Telemetry.ActivitySource.StartActivity("CreateOrder"))
      		{
      			activity?.AddTag("order.id", orderDto.UserId);
      			activity?.AddTag("order.items", string.Join(", ", orderDto.Items.Select(i => i.ProductId)));
    
      			// 应用层逻辑:数据验证
      			if (orderDto.Items == null || orderDto.Items.Count == 0)
      			{
      				throw new ArgumentException("Order items are required.");
      			}
    
      			// 创建订单本地事务
      			var order = new Order
      			{
      				UserId = orderDto.UserId,
      				Items = orderDto.Items.Select(itemDto => new OrderItem
      				{
      					ProductId = itemDto.ProductId,
      					Quantity = itemDto.Quantity
      				}).ToList(),
      				TotalAmount = orderDto.Items.Sum(itemDto => itemDto.Price * itemDto.Quantity)
      			};
    
      			// 记录其他操作
      			activity?.AddEvent(new ActivityEvent("Order created"));
    
      			// 调用其他服务
      			var paymentService = new PaymentService(_httpClient);
      			paymentService.ProcessPayment(order.Id, order.TotalAmount);
      		}
      	}
      }
    
      public class PaymentService
      {
      	private readonly HttpClient _httpClient;
    
      	public PaymentService(HttpClient httpClient)
      	{
      		_httpClient = httpClient;
      	}
    
      	public void ProcessPayment(long orderId, decimal amount)
      	{
      		using (var activity = Telemetry.ActivitySource.StartActivity("ProcessPayment"))
      		{
      			activity?.AddTag("orderId", orderId);
      			activity?.AddTag("amount", amount);
    
      			// 处理支付逻辑
      			var response = _httpClient.PostAsync($"http://paymentservice/process/{orderId}", null).Result;
      			if (!response.IsSuccessStatusCode)
      			{
      				throw new InvalidOperationException("Payment processing failed.");
      			}
    
      			// 记录其他操作
      			activity?.AddEvent(new ActivityEvent("Payment processed"));
      		}
      	}
      }
    
      public class Program
      {
      	public static void Main(string[] args)
      	{
      		var tracerProvider = TracingConfig.InitTracer("order-service");
      		var httpClient = new HttpClient();
    
      		var orderService = new OrderService(tracerProvider, httpClient);
    
      		var orderDto = new OrderCreationDto
      		{
      			UserId = 123,
      			Items = new List<OrderItemDto>
      			{
      				new OrderItemDto { ProductId = 456, Quantity = 2, Price = 10.0m }
      			}
      		};
    
      		orderService.CreateOrder(orderDto);
      	}
      }
    

其他开源组件

  1. Prometheus + Grafana
  • Prometheus:一个开源的监控系统,可以收集和存储时间序列数据。
  • Grafana:一个开源的分析和监控平台,支持多种数据源,包括Prometheus。
  • 特点:
    • 主要用于监控指标数据,但也可以与追踪数据结合使用。
    • 支持强大的查询和可视化功能。
  1. ELK Stack (Elasticsearch, Logstash, Kibana)
  • Elasticsearch:一个分布式搜索和分析引擎。
  • Logstash:一个开源的数据收集引擎。
  • Kibana:一个开源的数据可视化工具。
  • 特点:
    • 提供强大的日志收集和可视化功能。
    • 可以与追踪数据结合使用,提供全面的监控和调试支持。
  1. Spring Cloud Sleuth (Java)
    • 由Spring Cloud提供的分布式追踪解决方案。
    • 支持B3、W3C TraceContext等上下文传播协议。
    • 可以与多种追踪后端集成,如Zipkin、Jaeger等。

集成示例:

	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-sleuth-zipkin</artifactId>
	</dependency>
  1. Steeltoe ( .NET)
  • 特点:

    • 由Pivotal提供的微服务工具集。
    • 支持分布式追踪、服务发现、配置管理等。
    • 可以与多种追踪后端集成,如Zipkin、Jaeger等。
  • 集成示例:

实现步骤

  1. 配置追踪库:
    • 选择合适的追踪库(如Jaeger、Zipkin、OpenTelemetry)并进行配置。
  2. 上下文传播:
    • 确保在服务之间的请求中传播追踪上下文信息。
  3. 收集追踪数据:
    • 使用追踪库自动收集服务中的追踪数据。
  4. 导出追踪数据:
    • 将收集到的追踪数据导出到集中式的存储系统或追踪后端。
  5. 可视化和分析:
    • 使用可视化工具(如Jaeger UI、Zipkin UI)来展示和分析追踪数据。

示例:使用OpenTelemetry进行追踪
以下是一个更详细的示例,展示如何在.NET应用中使用OpenTelemetry进行分布式追踪。

  1. 安装必要的NuGet包

     dotnet add package OpenTelemetry
     dotnet add package OpenTelemetry.Exporter.Jaeger
     dotnet add package OpenTelemetry.Instrumentation.AspNetCore
     dotnet add package OpenTelemetry.Instrumentation.HttpClient
    
  2. 配置OpenTelemetry

     using OpenTelemetry;
     using OpenTelemetry.Trace;
     using OpenTelemetry.Exporter.Jaeger;
     using OpenTelemetry.Instrumentation.AspNetCore;
     using OpenTelemetry.Exporter.OpenTelemetryProtocol;
     using OpenTelemetry.Instrumentation.HttpClient;
     using Microsoft.Extensions.DependencyInjection;
     public class TracingConfig
     {
     	public static TracerProvider InitTracer(string serviceName)
     	{
     		return Sdk.CreateTracerProviderBuilder()
     			.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(serviceName))
     			.AddHttpClientInstrumentation()
     			.AddAspNetCoreInstrumentation()
     			.AddJaegerExporter(o =>
     			{
     				o.AgentHost = "localhost";
     				o.AgentPort = 6831;
     			})
     			.Build();
     	}
     }
    
  3. 在应用程序中启用追踪

     using Microsoft.AspNetCore.Builder;
     using Microsoft.Extensions.DependencyInjection;
    
     public class Startup
     {
     	public void ConfigureServices(IServiceCollection services)
     	{
     		// 初始化OpenTelemetry追踪
     		TracingConfig.InitTracer("order-service");
    
     		services.AddControllers();
     	}
    
     	public void Configure(IApplicationBuilder app)
     	{
     		app.UseRouting();
     		app.UseEndpoints(endpoints =>
     		{
     			endpoints.MapControllers();
     		});
     	}
     }
    
  4. 在控制器中使用追踪

     using Microsoft.AspNetCore.Mvc;
     using OpenTelemetry.Context.Propagation;
     using System.Net.Http;
     using System.Threading.Tasks;
    
     [ApiController]
     [Route("api/[controller]")]
     public class OrderController : ControllerBase
     {
     	private readonly ITracer _tracer;
     	private readonly HttpClient _httpClient;
    
     	public OrderController(TracerProvider tracerProvider, HttpClient httpClient)
     	{
     		_tracer = tracerProvider.GetTracer("order-service");
     		_httpClient = httpClient;
     	}
    
     	[HttpPost]
     	public IActionResult CreateOrder(OrderCreationDto orderDto)
     	{
     		using (var span = _tracer.BuildSpan("CreateOrder").StartActive())
     		{
     			span.Span.SetTag("order.id", orderDto.UserId);
     			span.Span.SetTag("order.items", string.Join(", ", orderDto.Items.Select(i => i.ProductId)));
    
     			// 应用层逻辑:数据验证
     			if (orderDto.Items == null || orderDto.Items.Count == 0)
     			{
     				span.Span.SetTag("error", "Order items are required.");
     				return BadRequest("Order items are required.");
     			}
    
     			// 创建订单本地事务
     			var order = new Order
     			{
     				UserId = orderDto.UserId,
     				Items = orderDto.Items.Select(itemDto => new OrderItem
     				{
     					ProductId = itemDto.ProductId,
     					Quantity = itemDto.Quantity
     				}).ToList(),
     				TotalAmount = orderDto.Items.Sum(itemDto => itemDto.Price * itemDto.Quantity)
     			};
    
     			// 记录其他操作
     			span.Span.Log("Order created");
    
     			// 调用其他服务
     			var paymentService = new PaymentService(_tracer, _httpClient);
     			paymentService.ProcessPayment(order.Id, order.TotalAmount);
    
     			return Ok(order);
     		}
     	}
     }
    
     public class PaymentService
     {
     	private readonly ITracer _tracer;
     	private readonly HttpClient _httpClient;
    
     	public PaymentService(ITracer tracer, HttpClient httpClient)
     	{
     		_tracer = tracer;
     		_httpClient = httpClient;
     	}
    
     	public void ProcessPayment(long orderId, decimal amount)
     	{
     		using (var span = _tracer.BuildSpan("ProcessPayment").StartActive())
     		{
     			span.Span.SetTag("orderId", orderId);
     			span.Span.SetTag("amount", amount);
    
     			// 处理支付逻辑
     			var response = _httpClient.PostAsync($"http://paymentservice/process/{orderId}", null).Result;
     			if (!response.IsSuccessStatusCode)
     			{
     				span.Span.SetTag("error", "Payment processing failed.");
     				throw new InvalidOperationException("Payment processing failed.");
     			}
    
     			// 记录其他操作
     			span.Span.Log("Payment processed");
     		}
     	}
     }
    

关键点

  1. 上下文传播:
    • 确保在服务之间的请求中传播追踪上下文信息。
  2. 自动收集:
    • 使用OpenTelemetry的Instrumentation自动收集追踪数据。
  3. 导出追踪数据:
    • 使用Jaeger Exporter将追踪数据导出到Jaeger Collector。
  4. 可视化:
    • 使用Jaeger UI来展示和分析追踪数据。

总结

  • 分布式追踪:是一种监控和调试微服务中复杂请求调用链的技术。

  • 主要组件:

    • 追踪库:如Jaeger、Zipkin、OpenTelemetry等。
    • 上下文传播:如B3、W3C TraceContext等。
    • 数据存储:如Elasticsearch、Cassandra等。
    • 可视化工具:如Jaeger UI、Zipkin UI等。
  • OpenTelemetry:

    • 提供统一的API和SDK来收集和导出追踪数据。
    • 支持多种语言和框架。
    • 可以与多种后端集成。
  • 其他组件:

    • Jaeger:由Uber开发的开源分布式追踪系统。
    • Zipkin:由Twitter开发的开源分布式追踪系统。
    • Prometheus + Grafana:用于监控指标数据。
    • ELK Stack:用于日志收集和可视化。
    • Spring Cloud Sleuth:用于Java微服务的分布式追踪。
    • Steeltoe:用于.NET微服务的分布式追踪。

通过使用这些开源组件和策略,可以有效地实现微服务的分布式追踪,从而提高系统的监控能力和调试效率。

OpenTelemetry 官方文档
Jaeger 官方文档
Zipkin 官方文档
Steeltoe 官方文档

posted @ 2024-12-27 16:28  似梦亦非梦  阅读(15)  评论(0编辑  收藏  举报