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
"ReRoutes": [ // API01:CAS.ClientService // --> service part { ...... "HttpHandlerOptions": { "UseTracing": true // use butterfly to tracing request chain }, ...... }, // API02:CAS.ProductService // --> service part { ...... "HttpHandlerOptions": { "UseTracing": true // use butterfly to tracing request chain }, ...... }
(2)StartUp類中啟用OpenTracing
public void ConfigureServices(IServiceCollection services) { // Ocelot services.AddOcelot(Configuration) .AddOpenTracing(option => { option.CollectorUrl = Configuration["TracingCenter:Uri"]; option.Service = Configuration["TracingCenter:Name"]; }); ...... }
json配置文件了配置了Butterfly的Url地址及其顯示名:
"TracingCenter": { "Uri": "http://192.168.80.1:9618", // Tracing Center Address "Name": "API Gateway" // Display Name }
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
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); // Tracing - Butterfly services.AddButterfly(option => { option.CollectorUrl = Configuration["TracingCenter:Uri"]; option.Service = Configuration["TracingCenter:Name"]; }); services.AddSingleton<HttpClient>(p => new HttpClient(p.GetService<HttpTracingHandler>())); }
這里一起注入了加入了HttpTracingHandler的HttpClient,用來在Controller中調用其他服務接口。
(3)修改Controller中的Action,使其調用ClientService的一個接口:
public class HomeController : Controller { private string gatewayUri; public HomeController(IConfiguration configuration) { gatewayUri = $"http://{configuration["Gateway:IP"]}:{configuration["Gateway:Port"]}"; } ...... public IActionResult About([FromServices]HttpClient httpClient) { var requestResult = httpClient.GetStreamAsync($"{gatewayUri}/api/clientservice/trace").GetAwaiter().GetResult(); ViewData["Message"] = $"Your request data result : {requestResult}"; return View(); } ...... }
(4)在ClientService中,調用ProductService的一個接口:
[Route("api/Trace")] public class TraceController : Controller { private string gatewayUri; public TraceController(IConfiguration configuration) { gatewayUri = $"http://{configuration["Gateway:IP"]}:{configuration["Gateway:Port"]}"; } [HttpGet] public string Get([FromServices]HttpClient httpClient) { var result = httpClient.GetStringAsync($"{gatewayUri}/api/productservice/values").GetAwaiter().GetResult(); return $"ProductService AccessTime: {DateTime.Now.ToString()}, Result: {result}"; } }
(5)在ProductService中,提供這樣的一個接口,返回一些測試字符串
[Route("api/[controller]")] public class ValuesController : Controller { // GET api/values [HttpGet] public IEnumerable<string> Get() { return new string[] { "ProductService-value1", "ProductService-value2" }; } ...... }
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的作者