使用zipKin构建NetCore分布式链路跟踪

本文主要讲解使用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为:
1e8fb3c75c65c92a0f1c2de01ff49366.png

Exceplesstion日志记录信息为
abdfdde58235824b5e3ca13e49b3cca4.png

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

参考

本文引用文章连接如下:
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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/298018.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信又添新功能!这个微信群可以学英语,而且全程免费

全世界只有3.14 % 的人关注了爆炸吧知识最近不少网友发现&#xff0c;在微信群里居然可以学英语&#xff01;而且全程免费&#xff01;群里面会有免费的英语直播课&#xff0c;免费的课程资料&#xff0c;还有专业的英语老师辅导学习。 更重要的是&#xff0c;不需要集赞&#…

C# winform 窗体接收命令行参数自动登录进行系统,模拟600个WCF客户端的并发压力测试...

我们想要达到的目的是模拟&#xff16;&#xff10;&#xff10;个客户端的消息提醒功能&#xff0c;当然我们没有&#xff16;&#xff10;&#xff10;个电脑可以拿来测试&#xff0c;我们只有&#xff14;&#xff0d;&#xff15;台电脑可以用来测试&#xff0c;那我们就想…

UpdatePanel的用法

UpdatePanel控件也是Ajax里用得最多的控件之中的一个&#xff0c;UpdatePanel控件是用来局部更新网页上的内容&#xff0c;网页上要局部更新的内容必须放在UpdatePanel控件里&#xff0c;他必须和上一次说的ScriptManager控件一起使用。如今来看UpdatePanel的属性UpdatePanel重…

JMeter压测笔记

每个资深测试工程师&#xff0c;必须掌握的测试工具&#xff0c;熟练使用Jmeter能大大提高工作效率。熟练使用Jmeter后&#xff0c; 能用Jmeter搞定的事情&#xff0c;你就不会使用LoadRunner了。Jmeter 是一款使用Java开发的&#xff0c;开源免费的&#xff0c;测试工具&#…

系统同传软件_如何戴耳机录制自己的同传练习?

在学校上课的话&#xff0c;有同传实验室的模拟会议系统可以完成同传的录制&#xff0c;但是自己的练习的时候就会出现录制的问题。曾经在一次导专课上遇到过这种尴尬&#xff0c;由于需要将自己的同传练习录音分享给老师和同学听&#xff0c;所以就要把源语和译入语都录制下来…

颜宁课题组再发Cell!1个月时间内4篇顶刊!

全世界只有3.14 % 的人关注了爆炸吧知识本文来源&#xff1a;iNature&#xff08;作者&#xff1a;枫叶&#xff09;、微博转自&#xff1a;募格学术6月15日晚&#xff0c;颜宁团队和新南威尔士大学杨洪远团队合作&#xff0c;在Cell 《细胞》在线发表了题为“Structural Basis…

BOOST 线程完全攻略 - 结束语

2019独角兽企业重金招聘Python工程师标准>>> 全文介绍了3个boost::thread的扩展类&#xff0c;希望能给大家书写多线程代码带来便捷。 thread -> controlled_module_ex ->controlled_module 那么我们具体在什么情况下选用不同的扩展类呢&#xff1f; 1.如果你…

.NET Core使用Nlog记录日志

NLog是适用于各种.NET平台&#xff08;包括.NET标准&#xff09;的灵活&#xff0c;免费的日志记录平台。NLog使写入多个目标变得容易 。&#xff08;数据库&#xff0c;文件&#xff0c;控制台&#xff09;并即时更改日志记录配置。NLog支持结构化 和传统日志记录。NLog的重点…

动态路由协议(RIP)

动态路由协议包括距离矢量路由协议和链路状态路由协议。RIP&#xff08;Routing InformationProtocols&#xff0c;路由信息协议&#xff09;是使用最广泛的距离矢量路由协议。RIP 是为小型网络环境设计的&#xff0c;因为这类协议的路由学习及路由更新将产生较大的流量&#x…

这几道挑战极限的烧脑题,烧脑到爽爽爽爽爽!

▲ 点击查看 在美国&#xff0c;有一个天才儿童计划&#xff0c;选拔一批“天才”儿童进入天才班。这个计划是为了保证每个人接受平等教育机会的同时&#xff0c;也为精英成长提供合适的土壤。美国所谓的天才和精英是怎样的标准呢&#xff1f;进入天才班的儿童首先要通过一个叫…

WPF 跟随拖动改变的三次贝塞尔曲线思路

代码不多&#xff0c;思路也很简单&#xff0c;先看看效果&#xff1a;简单示例&#xff0c;所有代码都在MainWindow.xaml和MainWindow.xaml.cs内&#xff0c;Xaml代码&#xff1a;<Window x:Class"WPFDemos.MainWindow"xmlns"http://schemas.microsoft.com/…

php语言难点,PHP知识难点TOP3,挑战一下你

PHP知识难点TOP3,挑战一下你这里有新鲜出炉的PHP设计模式&#xff0c;程序狗速度看过来&#xff01;PHP开源脚本语言PHP(外文名: Hypertext Preprocessor&#xff0c;中文名&#xff1a;“超文本预处理器”)是一种通用开源脚本语言。语法吸收了C语言、Java和Perl的特点&#xf…

thymeleaf加载不了js引用_网站首页加载慢解决方案

打开网页&#xff0c;用户最满意的时间是2-5秒&#xff0c;如果用户等待超过10秒&#xff0c;99%的用户会关闭这个网页。那么&#xff0c;是什么原因会导致网站打开慢&#xff1f;又有什么办法解决呢&#xff1f;一般来说&#xff0c;http请求过多、网页过大、服务器性能过差等…

基础设备----笔记

插一条&#xff1a;OSI七层网络模型网络设备调制解调器&#xff1a;将数据&#xff0c;在数字信号和模拟信号之间转换网卡&#xff1a;基本数据转换、信息包的装配和拆装、网络存取控制、数据缓存、生成网络信号等。网卡按主板总线类型分类&#xff1a;ISA---分为8位和16位两种…

黑客大佬:我是如何让50个文件一起骗过AI安防系统的?

全世界只有3.14 % 的人关注了爆炸吧知识转自&#xff1a;大数据文摘编译&#xff1a;邢畅、张睿毅、钱天培你有没有想过当黑客呢&#xff1f;破解手机密码&#xff0c;黑入公司系统&#xff0c;甚至…控制全球电脑。打住打住&#xff01;违法犯罪的念头显然不能有。再退一步讲&…

WTM框架使用技巧之:CI/DI(持续集成/持续部署)

快点关注我们吧作者介绍王晓东&#xff0c;从事工业物联网行业多年&#xff0c;深入了解纺织、汽车零部件等制造业业务。开发过MES、WCS、SCADA、智能产线、质量追溯、工业通讯、linux网关等系统。对跨平台部署、运维有一定经验。使用WTM框架提高了40%的开发效率&#xff0c;WT…

php 建立自己的框架,利用 Composer 一步一步构建自己的 PHP 框架(一)——基础准备...

“一个时代结束了&#xff0c;另一个时代开始了。”Framework Interoperability Group(框架可互用性小组)&#xff0c;简称 FIG&#xff0c;成立于 2009 年。FIG 最初由几位知名 PHP 框架开发者发起&#xff0c;在吸纳了许多优秀的大脑和强健的体魄后&#xff0c;提出了 PSR-0 …

python3 UnicodeEncodeError: 'ascii' 错误

2019独角兽企业重金招聘Python工程师标准>>> python 3.4 使用urllib.request.urlopen() 打开url时候&#xff0c;如果url中包含中文&#xff0c;出现了“UnicodeEncodeError: ascii codec cant encode ”的错误&#xff0c;修复步骤如下 在url中有中文的地方加入…

女朋友的道歉方式

1 女朋友的道歉方式2 看吧,无聊的时候什么事都干得出来3 这猫太坏了&#xff01;4 还以为是特效,原来是实物 5 叉子的妙用6 也太信任这块玻璃了吧……7 棉花糖炸酱面......大家感受一下你点的每个赞&#xff0c;我都认真当成了喜欢

单元测试(三)基本使用

介绍本文来演示一下同事教导后的写法&#xff0c;同样有些单元测试是为了演示而写的单元测试。本文使用组件&#xff1a;Xunit、Moq以及dotNet相关知识注&#xff1a;本文内容基于上一篇操作首先指定一个方法编写单元测试&#xff0c;并且要保证没有其他因素干扰的情况下去进行…