Tip: 此篇已加入.NET Core微服务基础系列文章索引
一、什么是Tracing?
微服务的特点决定了功能模块的部署是分布式的,以往在单应用环境下,所有的业务都在同一个服务器上,如果服务器出现错误和异常,我们只要盯住一个点,就可以快速定位和处理问题,但是在微服务的架构下,大部分功能模块都是单独部署运行的,彼此通过总线交互,都是无状态的服务,这种架构下,前后台的业务流会经过很多个微服务的处理和传递,我们会面临以下问题:
- 分散在各个服务器上的日志怎么处理?
- 如果业务流出现了错误和异常,如何定位是哪个点出的问题?
- 如何快速定位问题?
- 如何跟踪业务流的处理顺序和结果?
以前在单应用下的日志监控很简单,在微服务架构下却成为了一个大问题,如果无法跟踪业务流,无法定位问题,我们将耗费大量的时间来查找和定位问题,在复杂的微服务交互关系中,我们就会非常被动。因此,我们需要对其进行追踪,而这个时候Google公司广泛使用了分布式集群,为了应对自身大规模的复杂集群环境,Google公司研发了Dapper分布式跟踪系统,并发表了论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,给行业内分布式跟踪的实现提供了非常有价值的参考,该论文也成为了当前分布式跟踪系统的理论基础。
对于基础理论,这里涉及到OpenTracing,推荐看看吴晟的翻译的《OpenTracing文档中文版》。
二、Butterfly的基本使用
2.1 Butterfly简介
Butterfly是一个使用Open Tracing规范来设计追踪数据的开源追踪组件,作者Lemon,也是AspectCore的作者。目前Ocelot已集成Butterfly,我们只需要做很少的配置即可对经过网关的所有API服务进行Tracing。不过,貌似Lemon已不打算继续维护Butterfly而是推荐使用Apache SkyWalking来做生产环境的分布式追踪,同时他也加入了SkyWalking团队共同进行SkyWalking在多语言生态的推动。不过,就学习而言,Butterfly是比较适合学习来了解分布式追踪是个神马玩意儿的,这里呢我暂时不再去学习ApacheSkyWalking了(因为我的目标是了解整个流程,做POC而不是能上生产环境的产品)。
这里是SkyWalking-netcore的GitHub地址:https://github.com/OpenSkywalking/skywalking-netcore
2.2 Butterfly的安装与配置
Step1.下载最新的release,目前是preview-0.0.8
Step2.解压并通过命令启动:dotnet Butterfly.Web.dll –EnableHttpCollector=true
Step3.通过默认地址和端口进行查看,如下图所示:(这里没有任何trace,因为还没有任何请求)
三、结合Ocelot的一个Tracing实例
3.1 Ocelot的配置
刚刚说到Ocelot已内集成了Butterfly,所以我们只需要做以下两个配置:
(1)配置文件配置UseTracing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 1 "ReRoutes": [
2 // API01:CAS.ClientService
3 // --> service part
4 {
5 ......
6 "HttpHandlerOptions": {
7 "UseTracing": true // use butterfly to tracing request chain
8 },
9 ......
10 },
11 // API02:CAS.ProductService
12 // --> service part
13 {
14 ......
15 "HttpHandlerOptions": {
16 "UseTracing": true // use butterfly to tracing request chain
17 },
18 ......
19 }
20
(2)StartUp类中启用OpenTracing
1
2
3
4
5
6
7
8
9
10
11
12 1 public void ConfigureServices(IServiceCollection services)
2 {
3 // Ocelot
4 services.AddOcelot(Configuration)
5 .AddOpenTracing(option =>
6 {
7 option.CollectorUrl = Configuration["TracingCenter:Uri"];
8 option.Service = Configuration["TracingCenter:Name"];
9 });
10 ......
11 }
12
json配置文件了配置了Butterfly的Url地址及其显示名:
1
2
3
4
5 1 "TracingCenter": {
2 "Uri": "http://192.168.80.1:9618", // Tracing Center Address
3 "Name": "API Gateway" // Display Name
4 }
5
3.2 案例结构与配置
这里我们模拟一个ASP.NET Core MVC Web应用程序中要请求一个ClientService的某个接口,而这个接口又依赖于ProductService的一个接口的返回结果,因此这个请求的请求顺序就如上图所示(标有序号),流程很简单,下面我们就来一一为MVC WebApp、ClientService和ProductService进行Butterfly的配置。
这里我们通过介绍MvcApp的配置(事先创建一个ASP.NET Core MVC应用程序)来说明如何安装和配置Buttefly,至于ClientService和ProductService和MvcApp的安装配置步骤一样,就不再赘述。
(1)NuGet安装Butterfly Client
NuGet>Install-Package Butterfly.Client.AspNetCore
*.这里建议安装0.0.7版本,0.0.8版本测试时始终无法获取请求。
(2)注册Butterfly
1
2
3
4
5
6
7
8
9
10
11
12
13 1 public void ConfigureServices(IServiceCollection services)
2 {
3 services.AddMvc();
4
5 // Tracing - Butterfly
6 services.AddButterfly(option =>
7 {
8 option.CollectorUrl = Configuration["TracingCenter:Uri"];
9 option.Service = Configuration["TracingCenter:Name"];
10 });
11 services.AddSingleton<HttpClient>(p => new HttpClient(p.GetService<HttpTracingHandler>()));
12 }
13
这里一起注入了加入了HttpTracingHandler的HttpClient,用来在Controller中调用其他服务接口。
(3)修改Controller中的Action,使其调用ClientService的一个接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 1 public class HomeController : Controller
2 {
3 private string gatewayUri;
4
5 public HomeController(IConfiguration configuration)
6 {
7 gatewayUri = $"http://{configuration["Gateway:IP"]}:{configuration["Gateway:Port"]}";
8 }
9
10 ......
11
12 public IActionResult About([FromServices]HttpClient httpClient)
13 {
14 var requestResult = httpClient.GetStreamAsync($"{gatewayUri}/api/clientservice/trace").GetAwaiter().GetResult();
15
16 ViewData["Message"] = $"Your request data result : {requestResult}";
17
18 return View();
19 }
20
21 ......
22 }
23
(4)在ClientService中,调用ProductService的一个接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 1 [Route("api/Trace")]
2 public class TraceController : Controller
3 {
4 private string gatewayUri;
5
6 public TraceController(IConfiguration configuration)
7 {
8 gatewayUri = $"http://{configuration["Gateway:IP"]}:{configuration["Gateway:Port"]}";
9 }
10
11 [HttpGet]
12 public string Get([FromServices]HttpClient httpClient)
13 {
14 var result = httpClient.GetStringAsync($"{gatewayUri}/api/productservice/values").GetAwaiter().GetResult();
15
16 return $"ProductService AccessTime: {DateTime.Now.ToString()}, Result: {result}";
17 }
18 }
19
(5)在ProductService中,提供这样的一个接口,返回一些测试字符串
1
2
3
4
5
6
7
8
9
10
11
12
13 1 [Route("api/[controller]")]
2 public class ValuesController : Controller
3 {
4 // GET api/values
5 [HttpGet]
6 public IEnumerable<string> Get()
7 {
8 return new string[] { "ProductService-value1", "ProductService-value2" };
9 }
10
11 ......
12 }
13
3.3 简单测试
(1)浏览器中访问MvcWebApp的About页面
(2)在Butterfly Web页面查看Trace
上图我们可以看到总花费时间,经历了哪些节点等信息。
上图我们可以看出调用的顺序,依次经历哪些节点,花费时间,占比等等。
(3)在Butterfly Web页面查看Dependencies
上图我们可以直观地看出这个请求的处理流程(MvcApp->API Gateway->ClientService->API Gateway->ProductService),经过了哪些节点,像API Gateway和ClientService就有一个双向连接,代表各自请求对方。
四、小结
本篇首先介绍了一下追踪(Tracing)的背景以及基本概念,然后介绍了一下一个开源的分布式追踪组件Butterfly,由于Ocelot已经集成了Butterfly,所以我们可以很方便地在Ocelot中使用Butterfly进行追踪。最后,通过一个具体的小实例,介绍了如何在ASP.NET Core微服务环境中如何使用Ocelot+Butterfly进行请求的追踪。不过,Butterfly的作者Lemon已不打算继续维护Butterfly而是推荐使用Apache SkyWalking来做生产环境的分布式追踪,同时他也加入了SkyWalking团队共同进行SkyWalking在多语言生态的推动。所以,学习环境下,可以拿Butterfly了解一下分布式追踪的意义,但是要上实际环境,可以考虑用以下SkyWalking。后续,有机会的话,我也会用SkyWalking来替代Butterfly做追踪,到时有机会也分享一下。
示例代码
Click Here => 点我下载
参考资料
作者不详,《微服务架构下,如何实现分布式跟踪?》
吴晟,《OpenTracing文档中文版》
桂素伟,《Ocelot中使用Butterfly实践》
张善友,《Ocelot集成Butterfly实现分布式追踪》
Butterfly Github:https://github.com/liuhaoyang/butterfly => 作者Lemon,也是AspectCore的作者