本文主要讲解使用ZipKin构建NetCore分布式链路跟踪


场景

因为最近公司业务量增加,而项目也需要增大部署数量,K8S中Pod基本都扩容了一倍,新增了若干物理机,部分物理机网络通信存在问题,导致部分请求打入有问题的物理机时总会出现超时的情况,由于之前系统中没有使用链路跟踪,导致排查问题比较慢,所以就去研究了市面上的链路框架,结果发现了ZipKin这款比较轻量级的链路跟踪框架。


实例代码

本文日志系统采用Exceplesstion
示例代码请求链路为SimpleZipkin(网关服务)--->WebApi(Api服务)--->OrderApi(订单服务)
首先创建公用类库,引用以下包(本文以1.5.0版本为例)
如果部署Zipkin使用的是Mysql作为存储,切记Mysql版本不要高于8.0,Zipkin暂不支持8.0的版本

zipkin4net
zipkin4net.middleware.aspnetcore

创建ZipKin帮助类

public static class ZipKinExtensions{public static IServiceCollection AddZipKin(this IServiceCollection services){return services.AddSingleton<HttpDiagnosticSourceObserver >();}public static IApplicationBuilder UseZipKin(this IApplicationBuilder app, IHostApplicationLifetime lifetime, ILoggerFactory loggerFactory, string serviceName, string zipKinUrl){DiagnosticListener.AllListeners.Subscribe(app?.ApplicationServices?.GetService<TraceObserver>());lifetime.ApplicationStarted.Register(() =>{TraceManager.SamplingRate = 1.0f;//记录数据密度,1.0代表全部记录var logger = new TracingLogger(loggerFactory, "zipkin4net");var httpSender = new HttpZipkinSender(zipKinUrl, "application/json");var tracer = new ZipkinTracer(httpSender, new JSONSpanSerializer(), new Statistics());var consoleTracer = new zipkin4net.Tracers.ConsoleTracer();TraceManager.RegisterTracer(tracer);TraceManager.RegisterTracer(consoleTracer);TraceManager.Start(logger);});lifetime.ApplicationStopped.Register(() => TraceManager.Stop());app.UseTracing(serviceName);//这边的名字可自定义return app;}}

Exceptionless帮助类

/// <summary>/// 日志扩展类/// </summary>public static class LogHelper{/// <summary>/// 记录Info日志/// </summary>/// <param name="logger"></param>/// <param name="message"></param>public static void InformationToException(this ILogger logger, string message){var tranceId = Trace.Current?.CurrentSpan.TraceId.ToString("x16");logger.LogInformation($@"tranceId={tranceId},日志主体为:{message}");}/// <summary>/// 记录Debug日志/// </summary>/// <param name="logger"></param>/// <param name="message"></param>public static void DebugToException(this ILogger logger, string message){var tranceId = Trace.Current?.CurrentSpan.TraceId.ToString("x16");logger.LogDebug($@"tranceId={tranceId},日志主体为:{message}");}/// <summary>/// 记录错误日志/// </summary>/// <param name="logger"></param>/// <param name="message"></param>public static void ErrorToException(this ILogger logger, string message){var tranceId = Trace.Current?.CurrentSpan.TraceId.ToString("x16");logger.LogError($@"tranceId={tranceId},日志主体为:{message}");}/// <summary>/// 记录追踪日志/// </summary>/// <param name="logger"></param>/// <param name="message"></param>public static void TraceToException(this ILogger logger, string message){var tranceId = Trace.Current?.CurrentSpan.TraceId.ToString("x16");logger.LogTrace($@"tranceId={tranceId},日志主体为:{message}");}/// <summary>/// 记录警告日志/// </summary>/// <param name="logger"></param>/// <param name="message"></param>public static void WarningToException(this ILogger logger, string message){var tranceId = Trace.Current?.CurrentSpan.TraceId.ToString("x16");logger.LogWarning($@"tranceId={tranceId},日志主体为:{message}");}}

接下来创建SimpleZipkin、WebApi、OrderApi等项目(因为结构一致,所以本文只创建一个),首先引用Exceplesstion

public class Program{public static void Main(string[] args){CreateHostBuilder(args).Build().Run();}public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).ConfigureLogging((hostContext, configLogging) =>{configLogging.AddConfiguration(hostContext.Configuration.GetSection("Logging"));configLogging.AddConsole();configLogging.AddDebug();configLogging.AddExceptionless();ExceptionlessClient.Default.Configuration.SetDefaultMinLogLevel(Exceptionless.Logging.LogLevel.Debug);configLogging.SetMinimumLevel(LogLevel.Debug);                   }).ConfigureWebHostDefaults(webBuilder =>{webBuilder.UseStartup<Startup>();});}

接下来在Startup中引入ZipKin

public void ConfigureServices(IServiceCollection services){// 注入Rpc//AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);//services.AddGrpcClient<HelloServer.HelloServerClient>((p, o) =>//{//    o.Address = new Uri("http://127.0.0.1:3848");//});//.AddHttpMessageHandler(provider => TracingHandler.WithoutInnerHandler("RpcService"));services.AddControllers();services.AddZipKin();services.AddSingleton<IDiagnosticSource, HttpDiagnosticSourceDemo>();services.AddHttpClient("webApi", client => { client.BaseAddress = new Uri($"http://localhost:5001"); });services.AddSwaggerGen(c =>{c.SwaggerDoc("v1", new OpenApiInfo { Title = "SimpleZipKin", Version = "v1" });});}public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory,IHostApplicationLifetime lifetime){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();app.UseSwagger();app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "SimpleZipkin v1"));}Configuration.GetSection("ExceptionLess").Bind(ExceptionlessClient.Default.Configuration);ExceptionlessClient.Default.Configuration.SetDefaultMinLogLevel(Exceptionless.Logging.LogLevel.Debug);app.UseZipKin(lifetime, loggerFactory, "SimpleZip", "http://127.0.0.1:9411");//SimpleZip修改为对应的应用名称,127.0.0.1地址切换为自己的zipkin地址  app.UseRouting();app.UseAuthorization();app.UseEndpoints(endpoints => { endpoints.MapControllers(); });}

接下来创建对应的Controller

[Route("/api/Home")]public class HomeController : Controller{private readonly IHttpClientFactory _httpClientFactory;private readonly ILogger _logger;/// <summary>/// 构造函数/// </summary>/// <param name="httpClientFactory"></param>/// <param name="logger"></param>public HomeController(IHttpClientFactory httpClientFactory, ILogger<HomeController> logger){_httpClientFactory = httpClientFactory;//_helloServerClient = helloServerClient;_logger = logger;}[HttpGet("GetZipKin")]public async Task<string> GetZipKin(){_logger.InformationToException($@"这里是SimpleZipKinApi");var httpClient = _httpClientFactory.CreateClient("webApi");var httpResult = await httpClient.GetAsync($"api/order/getorder");var result = await httpResult.Content.ReadAsStringAsync();return result;}    }

最后在appsettings.json中加入对应的Exceplesstionless配置

"ExceptionLess": {"ApiKey": "****************************","ServerUrl": "http://127.0.0.1:5000"}

OrderApi、WebApi如法炮制,修改对应的请求链路信息

接下来我们使用DiagnosticAdapter做链路记载,在公共类库中创建HttpDiagnosticListener类
DiagnosticSource是Runtime层提供,应用层可以通过它与系统集成、事件日志、以及性能计数器进行交互。
DiagnosticSource官方介绍:https://docs.microsoft.com/zh-cn/dotnet/api/system.diagnostics.diagnosticsource?view=net-5.0
关于DiagnosticSource设计参考原有yi念之间大佬的文章:https://www.cnblogs.com/wucy/p/13532534.html

public class HttpDiagnosticSourceDemo : IDiagnosticSourceDemo{public string DiagnosticName => "HttpDiagnosticSourceDemo";private ClientTrace _clientTrace;private readonly IInjector<HttpHeaders> _injector = Propagations.B3String.Injector<HttpHeaders>((carrier, key, value) => carrier.Add(key, value));[DiagnosticName("System.Net.Http.Request")]public void HttpRequest(HttpRequestMessage request){_clientTrace = new ClientTrace("simpleZipKin", request.Method.Method);if (_clientTrace.Trace != null){_injector.Inject(_clientTrace.Trace.CurrentSpan, request.Headers);}}[DiagnosticName("System.Net.Http.Response")]public void HttpResponse(HttpResponseMessage response){if (_clientTrace.Trace != null){_clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_PATH, response.RequestMessage.RequestUri.LocalPath));_clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_METHOD, response.RequestMessage.Method.Method));_clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_HOST, response.RequestMessage.RequestUri.Host));if (!response.IsSuccessStatusCode){_clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_STATUS_CODE, ((int)response.StatusCode).ToString()));}}}[DiagnosticName("System.Net.Http.Exception")]public void HttpException(HttpRequestMessage request, Exception exception){}}

IDiagnosticSourceDemo接口信息如下:

public interface IDiagnosticSourceDemo{string DiagnosticName { get; }}

HttpDiagnosticSourceObserver方法如下:

public class HttpDiagnosticSourceObserver : IObserver<DiagnosticListener>{private IEnumerable<IDiagnosticSourceDemo> _diagnosticSourceDemo;public HttpDiagnosticSourceObserver (IEnumerable<IDiagnosticSourceDemo> diagnosticSourceDemo){_diagnosticSourceDemo= diagnosticSourceDemo;}public void OnCompleted(){}public void OnError(Exception error){}public void OnNext(DiagnosticListener listener){var diagnosticSource= _diagnosticSourceDemo.FirstOrDefault(i => i.DiagnosticName == listener.Name);if (traceDiagnostic != null){//适配订阅listener.SubscribeWithAdapter(diagnosticSource);}}}

最终运行结果如下:
Zipkin为:

Exceplesstion日志记录信息为

通过Exceptionless记录的环境信息也能将对应的机器定位

参考

本文引用文章连接如下:
DiagnosticSource官方介绍:https://docs.microsoft.com/zh-cn/dotnet/api/system.diagnostics.diagnosticsource?view=net-5.0
DiagnosticSource参考连接:https://www.cnblogs.com/wucy/p/13532534.html
                   https://sudonull.com/post/3671-Using-the-DiagnosticSource-in-NET-Core-Theory
                   https://andrewlock.net/logging-using-diagnosticsource-in-asp-net-core/
docker部署Zipkin:https://www.cnblogs.com/binz/p/12658020.html
docekr部署exceptionless:https://www.cnblogs.com/edisonchou/p/exceptionless_v5_deployment_introduction.html

使用zipKin构建NetCore分布式链路跟踪相关推荐

  1. 使用OpenTelemetry搭配Zipkin构建NetCore分布式链路跟踪 | WebAPI + gRPC

    OpenTelemetry介绍 OpenTelemetry是一组标准和工具的集合,旨在管理观测类数据,如 trace.metrics.logs 等. 通过标准化不同的应用程序和框架如何收集和发出可观察 ...

  2. Spring Cloud Sleuth+Zipkin 构建微服务链路跟踪系统

    什么是链路跟踪系统? 在微服务中,多个服务分布在不同物理机器上,各个服务之间相互调用.如何清晰地记录服务调用过程,并在出现问题的时候能够通过查看日志和服务之间的调用关系来定位问题,这样的系统就叫做链路 ...

  3. 原理 | 分布式链路跟踪组件 SOFATracer 和 Zipkin 模型转换

    SOFA 中间件是蚂蚁金服自主研发的金融级分布式中间件,包含了构建金融级云原生架构所需的各个组件,包括微服务研发框架,RPC 框架,服务注册中心,分布式定时任务,限流/熔断框架,动态配置推送,分布式链 ...

  4. 跟我学SpringCloud | 第十一篇:使用Spring Cloud Sleuth和Zipkin进行分布式链路跟踪

    SpringCloud系列教程 | 第十一篇:使用Spring Cloud Sleuth和Zipkin进行分布式链路跟踪 Springboot: 2.1.6.RELEASE SpringCloud: ...

  5. SpringCloud技术指南系列(十五)分布式链路跟踪Sleuth与Zipkin实现

    SpringCloud技术指南系列(十五)分布式链路跟踪Sleuth与Zipkin实现 一.概述 分布式链路追踪,是一种用于分析和监控应用程序的方法,尤其是那些使用微服务架构的那些应用.分布式链路跟踪 ...

  6. 蚂蚁金服分布式链路跟踪组件 SOFATracer 总览 | 剖析 1

    2019新春支付宝红包技术大揭秘在线峰会将于03-07日开始,点击这里报名届时即可参与大牛互动. SOFA Scalable Open Financial Architecture 是蚂蚁金服自主研发 ...

  7. 蚂蚁金服分布式链路跟踪组件 SOFATracer 数据上报机制和源码分析 | 剖析

    2019新春支付宝红包技术大揭秘在线峰会将于03-07日开始,点击这里报名届时即可参与大牛互动. SOFA Scalable Open Financial Architecture 是蚂蚁金服自主研发 ...

  8. 11|链路追踪:如何定制一个分布式链路跟踪系统?

    11|链路追踪:如何定制一个分布式链路跟踪系统 ? 你好,我是徐长龙,这节课我们讲一讲如何实现分布式链路跟踪. 分布式链路跟踪服务属于写多读少的服务,是我们线上排查问题的重要支撑.我经历过的一个系统, ...

  9. 分布式链路跟踪中的 traceid 和 spanid 代表什么?

    在分布式服务架构下,一个 Web 请求从网关流入,有可能会调用多个服务对请求进行处理,拿到最终结果.这个过程中每个服务之间的通信又是单独的网络请求,无论请求经过的哪个服务出了故障或者处理过慢都会对前端 ...

最新文章

  1. javascript编写_如何通过编写自己的Web开发框架来提高JavaScript技能
  2. 清华、北邮等高校研究人员实现具有 160 个目标的基于 SSVEP 的免校准 BCI 系统...
  3. Linux内核源码中使用宏定义的若干技巧
  4. Python的序列切片
  5. 第四周课程总结试验报告(二)
  6. python 读取json为list及向json文件追加数据
  7. 解析大型.NET ERP系统 分布式应用模式设计与实现
  8. 网络基础知识(黑马教程笔记)-6-静态资源访问的功能实现
  9. 外包以小时计算金额的费用_软件外包价格如何计算?
  10. 全球免费开放的电子图书馆
  11. 苹果原壁纸高清_苹果iPhone全面屏桌面壁纸 第89期 苹果x手机专用高清壁纸
  12. (MATLAB)绘制三维曲线(plot3/plot)
  13. 开心网倒闭变卖,创始人程炳皓反思的亲笔信全文
  14. 在内网中使用maven_使用nexus搭建内网maven镜像
  15. 【阿里云】视频点播开通与配置
  16. 决策树分析例题经典案例_决策树分类的实例
  17. 打印自身源代码的程序
  18. centos查看CPU温度
  19. 如何打开小米,oppo,华为等手机的系统应用的指定页面
  20. 更新image的方法

热门文章

  1. 51CTO各位博友大家好!
  2. 谷歌街景新功能——帮警方抓毒贩
  3. 如何彻底卸载MySQL
  4. 如何添加JWT生成的token在请求头中
  5. 【算法学习】网络流模板……
  6. 关于photoshop
  7. NetBeans Weekly News 刊号 # 27 - Sep 24, 2008
  8. php post 获取xml,php 获取post的xml数据并解析示例
  9. apple tv 开发_如何跨多台Apple TV同步Apple TV的主屏幕
  10. C#如何用正则表达式截取https和带端口的域名