.NET Core 3.0 的新改进:针对分布式应用程序的故障诊断和监控

由于分布式应用是由多个组件组成的,且这些组件往往是由不同的团队拥有和操作,所以在与应用程序发生交互时,就会需要跨多个组件执行代码的分布式跟踪。如果用户遇到了问题,想要确定是哪个组件出现了差错,基本就是一件不可能完成的事情。

与单体应用程序相比,分布式应用程序的特点之一就是很难将单个分布式跟踪的遥测 (如日志) 关联起来。虽然用户可以通过查看日志了解到每个组件是如何处理每个请求的,但是很难知道一个组件中的请求和另一个组件中的请求是否属于同一分布式跟踪。

为了解决这个问题,应用性能管理厂商(APM)会提供从一个组件到另一个组件的分布式跟踪上下文传播功能。但是因为很多环境具有异构性、组件归属不同的团队,并通过不同的工具进行监视,因此对分布式应用程序进行一致的测试仍是难点。

随着 W3C Trace Contex 规范逐步过渡到 Proposed Recommendation maturity 级别,再加上其它供应商和平台对该规范的支持,上下文传播的复杂性正在降低。W3C Trace Contex 定义了分布式跟踪上下文的语义和格式,这使得分布式应用程序中的每个组件都可以理解上下文,并将其传播到调用的组件中。

为了使得分布式应用程序开发更容易,微软做了很多努力,例如 Orleans 框架和 Dapr 项目,而在分布式跟踪上下文传播,微软的服务和平台将采用 W3C Trace Contex 规范。同时,针对分布式跟踪和日志,.NET Core 3.0 做了很多新工作。

分布式跟踪和日志记录

.NET Core 3.0 在分布式跟踪方面的最新改进:

  • 两个开箱即用的.NET Core 3.0 应用程序在整个分布式跟踪中关联日志;

  • .NET Core 3.0 如何设置分布式跟踪上下文,如何自动跨 http 传播;

  • 同一个分布式跟踪标识如何被遥测 SDK 使用,例如 OpenTelemetry 和 ASP.NET Core logs。

为了帮助大家更深刻的理解.NET Core 3.0 的新改进,下面我们做了一个示例。

准备工作

该示例中,我们需要用到三个简单的组件:ClientApp、FrontEndApp 和 BackEndApp。BackEndApp 是一个名为 WeatherApp 的模板 ASP.NET Core 应用程序,可以通过公开的 REST API 来获取天气预报。而 FrontEndApp 会通过控制权将所有传入的请求发送给 BackEndApp。

[ApiController]


[Route("[controller]")]


public class WeatherForecastProxyController : ControllerBase


{


private readonly ILogger<WeatherForecastProxyController> _logger;


private readonly HttpClient _httpClient;


public WeatherForecastProxyController({1}

{1}

ILogger<WeatherForecastProxyController> logger,

{1}

HttpClient httpClient)


{


_logger = logger;


_httpClient = httpClient;


}


[HttpGet]


public async Task<IEnumerable<WeatherForecast>> Get()


{


var jsonStream = await


_httpClient.GetStreamAsync("http://localhost:5001/weatherforecast");


var weatherForecast = await


JsonSerializer.DeserializeAsync<IEnumerable<WeatherForecast>>(jsonStream);


return weatherForecast;


}


}


ClientApp 是一个 .NET Core 3.0 Windows Forms app,会调用 FrontEndApp 进行天气预报。

private async Task<string> GetWeatherForecast()


{


return await _httpClient.GetStringAsync(


"http://localhost:5000/weatherforecastproxy");


}

需要注意的是,在这段示例中,没有安装任何额外的 SDK 和库。

查看日志

我们通过 ClientApp 调用来观察 FrontEndApp 和 BackEndApp 生成的日志。

FrontEndApp :

info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]


=> ConnectionId:0HLR1BR0PL1CH


=> RequestPath:/weatherforecastproxy


RequestId:0HLR1BR0PL1CH:00000001,


SpanId:|363a800a-4cf070ad93fe3bd8.,


TraceId:363a800a-4cf070ad93fe3bd8,


ParentId:


Executed endpoint 'FrontEndApp.Controllers.WeatherForecastProxyController.Get (FrontEndApp)'


BackEndApp:

info: BackEndApp.Controllers.WeatherForecastController[0]


=> ConnectionId:0HLR1BMQHFKRL


=> RequestPath:/weatherforecast


RequestId:0HLR1BMQHFKRL:00000002,


SpanId:|363a800a-4cf070ad93fe3bd8.94c1cdba_,


TraceId:363a800a-4cf070ad93fe3bd8,


ParentId:|363a800a-4cf070ad93fe3bd8.


Executed endpoint 'FrontEndApp.Controllers.WeatherForecastController.Get (BackEndApp)'


与 magic 一样,来自两个独立应用程序的日志共享相同的 TraceId。ASP.NET Core 3.0 应用程序会初始化分布式跟踪上下文,并将其传递到头文件中。

FrontEndApp 并没有收到任何其它的头文件,出现这种情况的原因是在 ASP.NET Core 应用程序中,分布式跟踪是由 ASP.NET Core 框架自身在每次传入请求时启动的。

启动分布式跟踪

相信很多人都注意到了 Windows 窗体应用 ClientApp 和 ASP.NET Core FrontEndApp 在行为上的差异。ClientApp 未设置任何分布式跟踪上下文,因此 FrontEndApp 也不会收到。设置分布式操作最简单的方法是,使用 DiagnosticSource 包中名为 Activity 的 API。

private async Task<string> GetWeatherForecast()


{


var activity = new Activity("CallToBackend").Start();


try


{


return await _httpClient.GetStringAsync(


"http://localhost:5000/weatherforecastproxy");


}


finally


{


activity.Stop();


}


}

启动之后,HttpClient 就知道需要传播分布式跟踪上下文。需要注意的是,ClientApp、FrontEndApp 和 BackEndApp 都共享同一个 TraceId。

W3C Trace Context

上下文使用 Request-Id 进行传播,这是从 ASP 中引入的,是默认生效的。但是,W3C Trace Context 正被广泛采用,因此,我们建议切换到 W3C Trace Context 的上下文传播格式。

在.NET Core 3.0 中,切换到 W3C Trace Context 格式只需要在主方法中添加一行代码:

static void Main()


{


Activity.DefaultIdFormat = ActivityIdFormat.W3C;



Application.Run(new MainForm());


}

当 FrontEndApp 收到来自 ClientApp 的请求时,你会在请求中看到一个 traceparent 头文件:

通过这个头文件,.NET Core 应用程序就会明白现在需要通过 W3C Trace Context 格式来进行传播调用。需要注意的是,.NET Core 应用程序可以自动识别 W3C Trace Context 的正确格式,但是将分布式跟踪上下文的默认格式切换到 W3C Trace Context,可以在异构环境中实现更好的互操作性。

所有属性为 TraceId 和 SpanId 的日志:

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]


=> ConnectionId:0HLQV2BC3VP2T


=> RequestPath:/weatherforecast


RequestId:0HLQV2BC3VP2T:00000001,


SpanId:da13aa3c6fd9c146,


TraceId:f11a03e3f078414fa7c0a0ce568c8b5c,


ParentId:5076c17d0a604244


Request starting HTTP/1.1 GET http://localhost:5000/weatherforecast


OpenTelemetry 的 Activity 和分布式跟踪

OpenTelemetry 提供了一组 API、库、代理和控制器服务,用于从应用程序捕获分布式跟踪和度量。

在调用时启动 AddOpenTelemetry,就可以在 BackEndApp 上启用 OpenTelemetry:

services.AddOpenTelemetry(b =>


b.UseZipkin(o => {


o.ServiceName="BackEndApp";


o.Endpoint=new Uri("http://zipkin /api/v2/spans");


})


.AddRequestCollector());

FrontEndApp 日志中的 TraceId 与 BackEndApp 中的 TraceId 匹配。

info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2]


=> ConnectionId:0HLR2RC6BIIVO


=> RequestPath:/weatherforecastproxy


RequestId:0HLR2RC6BIIVO:00000001,


SpanId:54e2de7b9428e940,


TraceId:e1a9b61ec50c954d852f645262c7b31a,


ParentId:69dce1f155911a45


=> FrontEndApp.Controllers.WeatherForecastProxyController.Get (FrontEndApp)


Executed action FrontEndApp.Controllers.WeatherForecastProxyController.Get (FrontEndApp) in 3187.3112ms


info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2]


=> ConnectionId:0HLR2RLEHSKBV


=> RequestPath:/weatherforecast


RequestId:0HLR2RLEHSKBV:00000001,


SpanId:0e783a0867544240,


TraceId:e1a9b61ec50c954d852f645262c7b31a,


ParentId:54e2de7b9428e940


=> BackEndApp.Controllers.WeatherForecastController.Get (BackEndApp)


Executed action BackEndApp.Controllers.WeatherForecastController.Get (BackEndApp) in 3085.9111ms

此外,Zipkin 将报告相同的跟踪,因此,可以将分布式跟踪工具收集的分布式跟踪与来自计算机的日志关联起来。当 ClientApp 遇到问题时,可以将此 TraceId 提供给用户,由于用户和应用程序可以共享,因此能够更加容易的跨组件发现相应的日志和分布式跟踪。

另外,用户可以轻松启用对三个组件的监控,并在甘特图上查看:

ASP .NET Core 应用程序与分布式跟踪集成

APM 厂商收集到的遥测数据和 ASP .NET Core 使用的分布式跟踪上下文是相关的。因此,ASP .NET Core 3.0 应用程序非常适合不同团队拥有不同组件的场景。

例如,下图中的两个应用 A 和 C,启用了类似于 OpenTelemetry 的 SDK 遥测采集。如果不使用 ASP .NET Core 3.0,那么应用程序 B 就会“破坏”跟踪,导致分布式跟踪无法起作用。

在大多数部署中,ASP.NET Core 应用程序配置为启用基本日志记录,因此应用程序 B 将传播分布式跟踪上下文。而来自 A 和 C 的分布轨迹将相互关联。在以前的应用程序中,如果 ClientApp 和 BackEndApp 被感知,而 FrontEndApp 没有被感知,仍然可以看到分布式跟踪是相关的:

ASP.NET Core 应用程序非常适合服务网格环境。在服务网格部署中,上图中的 A 和 C 可以表示服务网格。为了让服务网格请求进入和离开组件 B,应用程序必须包含某些头文件。

虽然 Istio 能够自动发送 span,但是仍需要一些提示来连接整个跟踪。应用程序需要使用合适的 HTTP 头文件,以便在发送 span 消息时,能够正确关联到单个跟踪中。如果是采用 W3C Trace Context 格式,ASP.NET Core 应用程序则无需做任何改变。

传递附加上下文

如果你希望能够在分布式应用程序的组件之间共享更多上下文,可以添加以下属性:

private async Task<string> GetWeatherForecast()


{


var activity = new Activity("CallToBackend")


.AddBaggage("appVersion", "v1.0")


.Start();


try


{


return await _httpClient.GetStringAsync(


"http://localhost:5000/weatherforecastproxy");


}


finally


{


activity.Stop();


}


}


服务器端,在 FrontEndApp 和 BackEndApp 可以看到一个额外的头文件 Correlation-Context。

使用 Activity.Baggage:

var appVersion = Activity.Current.Baggage.FirstOrDefault(b => b.Key == "appVersion").Value;


using (_logger.BeginScope($"appVersion={appVersion}"))


{


_logger.LogInformation("this weather forecast is from random source");


}


作用域中包含 appVersion:

info: FrontEndApp.Controllers.WeatherForecastController[0]


=> ConnectionId:0HLQV353507UG


=> RequestPath:/weatherforecast


RequestId:0HLQV353507UG:00000001,


SpanId:37a0f7ebf3ecac42,


TraceId:c7e07b7719a7a3489617663753f985e4,


ParentId:f5df77ba38504846


=> FrontEndApp.Controllers.WeatherForecastController.Get (BackEndApp)


=> appVersion=v1.0


this weather forecast is from random source


未来发展

随着 ASP.NET Core 3.0 的改进,很多 ASP .NET Core 包含的功能可能就难以使用了,比如开发人员和 DevOps 想要做一个交钥匙遥测解决方案,需要和很多 APM 的厂商来做。但是,我们在 OpenTelemetry 方面会加大投入,使得更多 ASP .NET Core 用户能够在监控和故障排除方面变得更容易。

我们会帮助用户采用 W3C Trace Context,并且在 ASP .NET Core 的未来版本中可能将其作为默认的分布式跟踪上下文传播格式。

另外,我们还会专注于改进分布式上下文传播场景。与 Monolits 相比,分布式应用程序在单个分布式跟踪的生存期缺少公共共享状态,而这种共享状态可以用于基本的日志记录、用于请求的高级路由、实验、A/B 测试、业务上下文传播等。

原文链接:

https://devblogs.microsoft.com/aspnet/improvements-in-net-core-3-0-for-troubleshooting-and-monitoring-distributed-apps/

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

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

相关文章

【翻译】.NET Core3.1发布

.NET Core3.1发布我们很高兴宣布.NET Core 3.1的发布。实际上&#xff0c;这只是对我们两个多月前发布的.NET Core 3.0的一小部分修复和完善。最重要的是.NET Core 3.1是长期支持&#xff08;LTS&#xff09;版本&#xff0c;并且将支持三年。和过去一样&#xff0c;我们希望花…

JVM(1)——JVM内存分区

一、JVM简介 JVM&#xff0c;即Java虚拟机&#xff08;Java Virtual Machine&#xff09;&#xff0c;一种能够运行Java bytecode的虚拟机&#xff0c;是Java实现跨平台的基础。 引入Java语言虚拟机后&#xff0c;Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚…

使用Azure Pipelines从GitHub发布NuGet包

[本文目录]ps: 阅读本文大概需要20分钟欢迎大家点击上方公众号链接关注我&#xff0c;了解新西兰码农生活什么是 YAML?name/value 名称/值collections 集合multiple data types 复合数据类型comments 注释Pipelines 的 YAML 结构在 Azure DevOps Pipelines 中创建第一个任务为…

JVM(2)——JVM类加载机制

一、JVM类加载机制简介 虚拟机把描述类的数据从Class文件加载到内存&#xff0c;并对数据进行校验、转换解析和初始化&#xff0c;最终形成可以被虚拟机直接使用的Java类型&#xff0c;这就是虚拟机的类加载机制。 在Java语言里面&#xff0c;类型的加载和连接过程都是在程序运…

PYPL 12月榜单发布,编程语言、IDE与数据库市场如何?

PYPL&#xff08;PopularitY of Programming Language&#xff0c;编程语言流行指数&#xff09;12 月份的榜单已经发布了。PYPL 是非常流行的参考指标&#xff0c;其榜单数据的排名均是根据榜单对象在 Google 上相关的搜索频率进行统计排名&#xff0c;原始数据来自 Google Tr…

JVM(3)——JVM类加载器

一、类加载器简介 虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现&#xff0c;以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块被称为“类加载器”。 类加载器虽然只用于实现类的…

.NET Core应用框架AA介绍(二)

AA的开源地址https://github.com/ChengLab/AAFrameWork AA框架是一个基础应用框架&#xff0c;是建立在众多大家熟知的流行工具之上并与之集成。比如&#xff1a;ASP.NET Core、Automapper、Dapper、Dapper-FluentMap、RabbitMQ、Redis、MassTransit、Log4net等等大家可以很方便…

JVM(4)——对象访问

一、对象创建过程在Java语言中&#xff0c;对象是如何访问的呢&#xff1f;对象访问在Java语言中无处不在&#xff0c;是最普通的程序行为&#xff0c;但即使是最简单的访问&#xff0c;也会涉及Java虚拟机栈、Java堆区、方法区。 对于下面这行代码&#xff0c; Object obj ne…

鹅厂后台开发工程师的工作日常

写在前面 &#xff1a;本故事纯属虚构&#xff0c;如有雷同&#xff0c;不负责任。为了整理 Linux 开发和日常使用的常用命令&#xff0c;想了好几天才串了这么个故事。虽然有点牵强&#xff0c;但是内容还是挺干的~欢迎大家点评。在很久很久以前&#xff0c;鹅厂开发类工程师职…

.NET Core开发的iNeuOS工业互联网平台,发布 iNeuDA 数据分析展示组件,快捷开发图形报表和数据大屏...

经过一段时间的努力&#xff0c;iNeuDA产品组件已经开发和测试完成&#xff0c;现在正式上线。现在iNeuOS工业互联网操作系统的技术体系和产品体系更佳完善&#xff0c;为中小企业提供更佳全面解决方案。如下图&#xff1a;iNeuDA 一站式大数据分析平台作为国内领先的新一代自助…

asp.net core 从 3.0 到 3.1

asp.net core 从 3.0 到 3.1Intro今天 .net core 3.1 正式发布了&#xff0c;.net core 3.1 正式版已发布&#xff0c;3.1 主要是对 3.0 的 bug 修复&#xff0c;以及一些小优化&#xff0c;而且作为 LTS 版本&#xff0c;建议大家升级。值得一提的是.net core 2.2 这个月就要寿…

身边的设计模式(三):抽象工厂 与 依赖注入

上篇文章&#xff0c;我们说到了简单工厂和工厂方法&#xff0c;如果没看过的&#xff0c;请先看上篇&#xff0c;不然的话&#xff0c;可能有些吃力&#xff0c;或者直接点击阅读原文&#xff0c;查看我博客园的对应详细版的文章。大家学到了这里&#xff0c;我建议自己可以练…

Java基础知识——Java集合详解

数组是Java很常见的一种数据结构&#xff0c;能够快速地进行存取。但是当遇到下面几种情况&#xff1a; ①我们需要存储的数据集数目是不定的 ②我们希望数据集能够自动排序 ③我们需要以键值对的方式存储数据 … 数组就不能满足我们的需求了。这时候&#xff0c;我们就需要使用…

边缘计算与云计算的不同,这篇说明白了!

术语“边缘计算”是指一种分布式计算&#xff0c;是将数据存储和计算带到需要它的站点或设备附近&#xff0c;这种分配设置消除了滞后时间并节省了带宽。与“物联网”相比&#xff0c;这是一种针对云环境的优化方法。它在数据源附近&#xff08;即网络的“边缘”&#xff09;处…

经典排序算法(12)——总结

一、排序算法简介 排序算法&#xff08;Sorting algorithm&#xff09;是一种能将一串数据&#xff0c;依照特定排序方式&#xff08;依照其中的某个或某些关键字的大小&#xff09;进行排列的一种算法。 常见的排序算法有&#xff1a;交换排序&#xff08;冒泡排序、快速排序&…

在Asp.Net Core MVC 开发过程中遇到的问题总结

1. Q: Razor视图中怎么添加全局模型验证消息A&#xff1a;使用ModelOnly<div asp-validation-summary"ModelOnly" class"text-danger"></div>2.Q&#xff1a;树形表格&#xff0c;使用的是bootstrap-tablejquery.treegridA&#xff1a;效果参考…

为什么子线程中不能直接更新UI

点击上方“dotNET全栈开发”&#xff0c;“设为星标”加“星标★”&#xff0c;每天11.50&#xff0c;好文必达全文约4000字&#xff0c;预计阅读时间8分钟当初有同事就碰到类似的问题&#xff0c;于是就总结了一些&#xff0c;那时写这篇文章是我还在第一家公司。今天有人提到…

解决问题的能力 10倍程序员

大家好&#xff0c;我是Z哥。今天我们聊的话题对大多数人来说应该都算是一个“痛点”&#xff0c;就是怎么提高自己解决问题的能力。我们的工作中&#xff0c;每天会遇到大大小小的很多问题。其中有些是之前从未遇到过的问题&#xff0c;这对很多人来说就会很棘手&#xff0c;不…

.NET Core 3.1正式发布,还不赶快升级!

点击蓝字关注我们 .NET Core 3.1于2019年12月3日正式发布&#xff0c;这是一个长期支持&#xff08;LTS&#xff09;版本&#xff0c;并且将支持三年&#xff0c;这个版本对.NET Core的许多方面进行了改进&#xff0c;建议您尽快升级。 .NET Core 3.1 的变更日志很小。唯一新增…

.NET Core Blazor 1-Blazor项目文件分析

简介Blazor是一个使用.NET技术用于代替JavaScript/typescript的前端WEB框架。在前端开发中使用.NET语言进行书写逻辑有利于我们的性能、可靠性和安全性。并且对于使用.NET开发人员而言&#xff0c;全栈的成本更低。截止文章发布时&#xff0c;.NET Core已经发布了3.1版本&#…