VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • C#网络编程之微服务监控与追踪(Prometheus、Jaeger)

第52章 微服务监控与追踪
52.1 微服务监控与追踪(Prometheus、Jaeger)
一、我踩过的监控坑:从“查日志查到崩溃”到“10分钟定位问题”
做微服务到第30个服务的时候,我遇到了这辈子最崩溃的问题:用户下单后订单状态一直是“待支付”,但支付服务明明收到了支付请求。我查了订单服务的日志、支付服务的日志、RabbitMQ的日志,整整花了3个小时才发现是Redis缓存过期导致订单状态更新失败——要是当时有vb.net教程C#教程python教程SQL教程access 2010教程全链路监控,10分钟就能定位到问题。后来我用Prometheus做监控,Jaeger做链路追踪,把所有服务的指标和链路数据统一收集,排查问题的效率直接提升了90%。这节我把这些踩坑经验揉进去,用大白话讲透微服务监控与追踪的核心原理,结合C#实战代码逐行拆解,拓展生产级优化技巧,让你的微服务从“黑盒”变成“透明盒”。
二、Prometheus:微服务监控的“瑞士军刀”,拉取式指标收集
Prometheus是开源的监控系统,核心是“拉取式指标+多维数据模型”,支持自定义指标、告警规则、多维查询,适合微服务的监控场景(如QPS、延迟、错误率、资源使用率)。
大白话解释:Prometheus是“上门收数据的快递员”
把Prometheus比作“快递员”:
1.Exporter:每个服务门口放一个快递箱,里面装着服务的指标数据(比如QPS、CPU使用率);
2.Prometheus:快递员定时上门收快递(拉取指标),把数据存到自己的仓库里;
3.Alertmanager:快递员发现快递箱里有异常数据(比如CPU使用率超过90%),就给你发告警短信;
4.Grafana:你把收到的快递拆开,做成可视化的仪表盘(比如QPS趋势图、延迟直方图)。
我踩过的坑:一开始用推送式监控(比如Zabbix),结果服务挂了之后监控系统收不到告警——换成Prometheus的拉取式,服务挂了之后Prometheus拉取不到数据,会直接触发告警,解决了“服务挂了但监控没告警”的问题!
实战1:Prometheus监控C#微服务(ASP.NET Core)
步骤1:部署Prometheus到K8s(或本地)
1.本地部署Prometheus:下载Prometheus二进制包,解压后修改prometheus.yml配置文件:
yaml

	global:
	scrape_interval: 15s # 每15秒拉取一次指标
	scrape_configs:
	- job_name: 'aspnetcore-app' # 任务名,随便起
	static_configs:
	- targets: ['localhost:5000'] # 你的C#服务地址

2.启动Prometheus:
bash

./prometheus --config.file=prometheus.yml

3.访问Prometheus UI:http://localhost:9090,输入up查询服务是否在线(1表示在线,0表示离线)。
步骤2:C#微服务集成Prometheus(Exporter)
2.1 安装NuGet包
bash
Install-Package prometheus-net.AspNetCore
2.2 配置Prometheus中间件(Program.cs)
csharp

	using prometheus_net;
	using prometheus_net.AspNetCore;
	
	var builder = WebApplication.CreateBuilder(args);
	
	// 1. 添加Prometheus服务
	builder.Services.AddMetricServer(); // 暴露指标端点(默认/metrics)
	builder.Services.AddCustomMetrics(); // 注册自定义指标
	
	var app = builder.Build();
	
	// 2. 启用Prometheus中间件
	app.UseHttpMetrics(); // 自动收集HTTP请求指标(QPS、延迟、错误率)
	app.UseMetricServer(); // 启用指标端点
	
	// 3. 业务接口
	app.MapGet("/api/orders", async () =>
	{
	// 记录自定义指标:订单查询次数
	Metrics.Counter("order_query_total", "Total number of order queries").Inc();
	await Task.Delay(100); // 模拟业务逻辑
	return Results.Ok(new { OrderId = "123", Status = "Paid" });
	});
	
	app.MapPost("/api/orders", async () =>
	{
	// 记录自定义指标:订单创建次数
	Metrics.Counter("order_create_total", "Total number of order creations").Inc();
	await Task.Delay(200); // 模拟业务逻辑
	return Results.Created("/api/orders/456", new { OrderId = "456", Status = "Created" });
	});
	
	app.Run();

逐行讲解:
1.AddMetricServer():注册Prometheus服务,默认暴露/metrics端点,Prometheus从这个端点拉取指标;
2.UseHttpMetrics():自动收集HTTP请求的核心指标,比如:
1.http_requests_total:总请求数(按方法、路径、状态码标签);
2.http_request_duration_seconds:请求延迟(直方图);
3.http_requests_in_flight:当前活跃请求数;
3.自定义指标:用Metrics.Counter创建计数器指标,记录订单查询和创建的次数;
4.指标类型:Prometheus支持4种核心指标类型:
1.Counter:只增不减的计数器(如总请求数、错误数);
2.Gauge:可增可减的仪表盘(如CPU使用率、内存使用率、活跃连接数);
3.Histogram:直方图(如请求延迟、响应大小);
4.Summary:摘要(如延迟的P95、P99分位数)。
2.3 自定义Gauge指标(监控Redis连接数)
csharp

	using prometheus_net;
	using StackExchange.Redis;
	
	public static class RedisMetrics
	{
	private static readonly Gauge _redisConnections = Metrics.Gauge(
	"redis_connections_total", 
	"Total number of active Redis connections");
	
	public static void RegisterRedisMetrics(IConnectionMultiplexer redis)
	{
	// 定时更新Redis连接数指标(每10秒更新一次)
	var timer = new System.Timers.Timer(10000);
	timer.Elapsed += (s, e) =>
	{
	var server = redis.GetServer("localhost:6379");
	var info = server.Info("stats");
	if (info.TryGetValue("total_connections_received", out var connections))
	{
	_redisConnections.Set(long.Parse(connections));
	}
	};
	timer.Start();
	}
	}
	
	// 在Program.cs中注册
	var redis = ConnectionMultiplexer.Connect("localhost:6379");
	RedisMetrics.RegisterRedisMetrics(redis);

逐行讲解:
Gauge指标:用于记录Redis的活跃连接数,可增可减;
定时更新:用Timer每10秒从Redis服务器获取连接数,更新指标值;
多维查询:可以在Prometheus中查询redis_connections_total的变化趋势,监控Redis的连接情况。
步骤3:配置Grafana可视化仪表盘
1.部署Grafana:下载Grafana二进制包,启动后访问http://localhost:3000(默认账号密码admin/admin);
2.添加Prometheus数据源:
点击左侧菜单“Connections”→“Data sources”→“Add data source”;
选择Prometheus,输入Prometheus地址http://localhost:9090,点击“Save & test”;
3.导入ASP.NET Core仪表盘:
点击左侧菜单“Dashboards”→“Import”;
输入仪表盘ID:12856(ASP.NET Core官方仪表盘),点击“Load”;
选择Prometheus数据源,点击“Import”;
4.查看仪表盘:可以看到服务的QPS、延迟、错误率、CPU使用率等指标的可视化图表。
拓展知识:Prometheus vs Zabbix

特性 Prometheus Zabbix
数据模型 多维标签 单维度
采集方式 拉取式 推送式
告警规则 基于PromQL 基于触发器
扩展性 强(支持自定义Exporter) 中(需要开发Agent)
适用场景 微服务、云原生 传统服务器监控

我踩过的坑:用Zabbix监控微服务,结果每个服务都要装Zabbix Agent,配置复杂——换成Prometheus,只需要在服务中集成Exporter,配置简单,扩展性强!
三、Jaeger:微服务链路追踪的“导航地图”,定位全链路延迟
Jaeger是开源的分布式链路追踪系统,核心是“追踪全链路请求路径”,支持多语言、多框架,适合微服务的链路追踪场景(如定位全链路延迟、排查跨服务调用问题)。
大白话解释:Jaeger是“快递追踪系统”
把Jaeger比作“快递追踪系统”:
1.Trace:一个完整的快递订单(比如用户下单的全链路请求);
2.Span:快递的每个环节(比如订单服务调用支付服务、支付服务调用Redis);
3.Parent Span:快递的上一个环节(比如订单服务是支付服务的Parent Span);
4.Jaeger UI:快递追踪页面,显示快递从下单到签收的全链路路径,每个环节的耗时。
我踩过的坑:微服务调用链路过长,某个环节延迟高但找不到是哪个服务——用Jaeger追踪后,直接看到是Redis查询延迟高,定位问题时间从3小时变成10分钟!
实战2:Jaeger追踪C#微服务(ASP.NET Core)
步骤1:部署Jaeger到本地(或K8s)
1.用Docker启动Jaeger:
bash

	docker run -d --name jaeger 
	-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 
	-p 5775:5775/udp 
	-p 6831:6831/udp 
	-p 6832:6832/udp 
	-p 5778:5778 
	-p 16686:16686 
	-p 14268:14268 
	-p 9411:9411 
	jaegertracing/all-in-one:1.50

2.访问Jaeger UI:http://localhost:16686,可以看到服务的链路追踪数据。
步骤2:C#微服务集成Jaeger(OpenTelemetry)
2.1 安装NuGet包
bash

	Install-Package OpenTelemetry.Extensions.Hosting
	Install-Package OpenTelemetry.Instrumentation.AspNetCore
	Install-Package OpenTelemetry.Exporter.Jaeger

2.2 配置OpenTelemetry(Program.cs)
csharp

	using OpenTelemetry;
	using OpenTelemetry.Trace;
	
	var builder = WebApplication.CreateBuilder(args);
	
	// 1. 添加OpenTelemetry服务
	builder.Services.AddOpenTelemetry()
	.WithTracing(tracing => tracing
	.AddAspNetCoreInstrumentation() // 自动追踪ASP.NET Core请求
	.AddHttpClientInstrumentation() // 自动追踪HttpClient调用
	.AddJaegerExporter(jaeger => // 导出到Jaeger
	{
	jaeger.AgentHost = "localhost"; // Jaeger Agent地址
	jaeger.AgentPort = 6831; // Jaeger Agent端口
	})
	.AddSource("OrderService") // 注册自定义Trace源
	);
	
	var app = builder.Build();
	
	// 2. 业务接口
	app.MapGet("/api/orders/{id}", async (string id, IHttpClientFactory httpClientFactory) =>
	{
	// 手动创建Span:订单查询环节
	using var activity = ActivitySourceProvider.Source.StartActivity("OrderService.QueryOrder");
	activity?.SetTag("order.id", id); // 添加自定义标签
	
	// 调用支付服务
	var httpClient = httpClientFactory.CreateClient();
	var paymentResponse = await httpClient.GetAsync($"http://localhost:5001/api/payments/{id}");
	paymentResponse.EnsureSuccessStatusCode();
	
	await Task.Delay(100); // 模拟业务逻辑
	return Results.Ok(new { OrderId = id, Status = "Paid" });
	});
	
	app.Run();

逐行讲解:
1.AddAspNetCoreInstrumentation():自动追踪ASP.NET Core的请求,生成Root Span;
2.AddHttpClientInstrumentation():自动追踪HttpClient的调用,生成Child Span;
3.AddJaegerExporter():把Trace数据导出到Jaeger Agent;
4.手动创建Span:用ActivitySource手动创建自定义Span,记录订单查询的环节,添加自定义标签(如订单ID);
5.Trace数据结构:每个Trace包含多个Span,每个Span有以下核心字段:
Trace ID:全链路唯一ID,标识一个完整的请求;
Span ID:当前环节的唯一ID;
Parent Span ID:上一个环节的Span ID;
Duration:当前环节的耗时;
Tags:自定义标签(如订单ID、服务名、错误信息)。
2.3 跨服务链路追踪(支付服务集成Jaeger)
在支付服务中做同样的配置,然后调用订单服务,就能在Jaeger UI中看到全链路的追踪数据:
1.访问订单服务的接口:http://localhost:5000/api/orders/123;
2.打开Jaeger UI,选择服务名OrderService,点击“Find Traces”;
3.点击某个Trace,可以看到全链路的Span:
GET /api/orders/{id}:Root Span(订单服务的请求);
GET /api/payments/{id}:Child Span(订单服务调用支付服务);
每个Span的耗时、标签、日志信息。
步骤3:配置链路采样策略
生产环境中,不需要追踪所有请求(会占用大量资源),可以配置采样策略:
csharp

	.WithTracing(tracing => tracing
	.SetSampler(new ParentBasedSampler(new TraceIdRatioBasedSampler(0.1))) // 采样10%的请求
	)

逐行讲解:
ParentBasedSampler:如果父Span被采样,子Span也会被采样;
TraceIdRatioBasedSampler:按比例采样(0.1表示采样10%的请求);
自定义采样:可以根据请求路径、用户ID等条件采样,比如只采样管理员的请求:
csharp

	.SetSampler(new ParentBasedSampler(new CustomSampler()))
	public class CustomSampler : Sampler
	{
	public override SamplingResult ShouldSample(in SamplingParameters samplingParameters)
	{
	if (samplingParameters.Attributes.TryGetValue("http.path", out var path) && path.ToString().Contains("/admin"))
	{
	return new SamplingResult(SamplingDecision.RecordAndSample);
	}
	return new SamplingResult(SamplingDecision.Drop);
	}
	}

拓展知识:Jaeger vs Zipkin

特性 Jaeger Zipkin
数据存储 支持Cassandra、Elasticsearch、Memory 支持Cassandra、Elasticsearch、MySQL
UI功能 强(支持多维查询、依赖图、Trace对比) 中(基础Trace查询)
性能 高(支持大量Trace数据) 中
扩展性 强(支持自定义采样、存储插件) 中
适用场景 微服务、云原生 传统分布式系统

我踩过的坑:用Zipkin追踪微服务,结果UI查询速度慢,依赖图显示不清晰——换成Jaeger后,UI查询速度快,依赖图直观,解决了“Trace数据多但查询慢”的问题!
四、生产级最佳实践与踩坑总结

  1. Prometheus最佳实践
    指标命名规范:用snake_case命名,比如order_query_total,不要用OrderQueryTotal;
    多维标签:给指标添加标签,比如http_requests_total{method="GET", path="/api/orders", status_code="200"},方便多维查询;
    告警规则:配置Alertmanager,比如CPU使用率超过90%触发告警,内存使用率超过80%触发告警;
    数据持久化:生产环境用Elasticsearch或TSDB存储Prometheus的指标数据,避免数据丢失;
    性能优化:对于高QPS的服务,用Histogram代替Summary,减少存储开销。
  2. Jaeger最佳实践
    采样策略:生产环境用比例采样(如10%),避免占用大量资源;
    自定义标签:给Span添加自定义标签(如订单ID、用户ID),方便排查问题;
    日志关联:把Trace ID和Span ID添加到服务的日志中,比如用Serilog:
    csharp
	Log.Information("Order {OrderId} processed successfully. TraceId: {TraceId}, SpanId: {SpanId}", 
	orderId, Activity.Current?.TraceId, Activity.Current?.SpanId);

依赖图分析:定期查看Jaeger的依赖图,发现不合理的服务调用(比如循环调用、跨团队调用);
性能优化:生产环境用Jaeger Collector代替Agent,减少网络开销。
3. 我踩过的坑总结
1.Prometheus拉取间隔过长:一开始设置每1分钟拉取一次,结果服务挂了1分钟后才告警——改成每15秒拉取一次,告警延迟从1分钟降到15秒;
2.Jaeger采样率过高:生产环境采样100%的请求,结果Jaeger存储占用了100GB磁盘空间——改成采样10%,存储占用降到10GB;
3.指标命名不规范:一开始用OrderQueryTotal命名指标,结果PromQL查询时要加引号——改成order_query_total,查询更方便;
4.链路追踪没关联日志:一开始Trace数据和日志数据分开,排查问题时要同时查两个系统——把Trace ID添加到日志中,用Trace ID就能找到对应的日志;
5.监控告警规则不全:一开始只监控CPU使用率,结果服务因为内存泄漏挂了但没告警——添加内存使用率、磁盘使用率、QPS、错误率的告警规则。
五、总结
Prometheus是微服务监控的核心,通过拉取式指标收集,实现服务的状态监控、性能分析、告警通知;Jaeger是微服务链路追踪的核心,通过全链路Trace数据,定位跨服务调用的延迟问题、错误问题。两者结合使用,能让你的微服务从“黑盒”变成“透明盒”,排查问题的时间从半天变成10分钟。
下一节我们会学习微服务的告警系统(Alertmanager+Grafana Alerting),解决“监控到异常但没人知道”的问题。

转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49572.html


相关教程