NET6 Core distributed tracing
分散式追蹤系統
系統架構從單體轉變成微服務之後,使用者發出的單次請求往往會涉及到多個服務之間的呼叫,以往採用的日誌服務也較難以窺見全貌,當我們需要追蹤某一次請求中間發生了那些事情,我們期望能獲取的資訊不外乎是這次的請求,總共經過哪些服務,每個服務花費了多久的時間,呼叫的順序等等,這就是分散式追蹤系統能夠幫我們做到的事情。只不過每一家系統的 API 都不太一樣,所以 W3C
也有提供一份Trace Context - W3C,讓大家都用同一個標準來實現分散式追蹤。
在這之前看到一堆像是 RequestId
, TraceId
, SpanId
, ParentId
, ActionId
,可能還有很多我沒有列出來的名詞,真的是有看沒有懂,現在至少可以從 W3C 的建議中明確知道一些名詞與他們的用途,其他的應該就是各家廠商自己的定義了,那就有用到再說囉
說明
依據 Trace Context - W3C。這份建議提供了一個標準的定義,讓各家廠商可以遵循,使得各家的追蹤系統可以不在各自為政。所以在version
為00
的情況下,traceparent
的格式就是下面這四個東西的組成
- version
- trace-id
- parent-id/span-id
- trace-flags
所以整個概念就像是下面這張圖一樣
這條呼叫鍊上,則是共用同一個 traceId
,每一個應用程式自己的 scope
就是用相同的 spanId
,在這條呼叫鍊的下一個應用程式則會是另外一個 spanId
,前一個應用程式需要將 traceparent
、tracestate
這兩個 header 資訊正確的傳遞給下一個應用程式。
事前準備
日誌服務:Seq
1 | # create volume folder |
分佈式追踪系統:zipkin
直接使用下列指令可以透過 docker 執行 zipkin,資料則是暫時儲存於記憶體中不保留,若需要保留資料,zipkin
也支援elasticSearch
、mySql
、cassandra
1 | docker run -d -p 9411:9411 openzipkin/zipkin-slim:2 |
測試專案
測試目標
確認當前 .NET6 Web 網站是否有遵循 W3C 的 traceparent context
測試情境
測試環境由三個應用程式構成
Web(clientApp) -> Proxy(FrontEndApp) -> WebAPI(BackEndApp)
範例程式碼:Github:distributed-tracing-demo
使用者透過瀏覽器開啟網頁,Web
從後端呼叫 Proxy
,而 Proxy
則轉發請求給 WebAPI
查詢取得資料後回應給使用者
測試步驟
開啟 clientApp
之後,透過中斷點檢視 FrontEndApp
跟 BackEndApp
的 request Header
frontEnd Header
backEnd Header
可以注意到 header 裡面的 keyValuePair 有一組是traceparent
, 00-6ef05abe949ce579cc110ab5b289df14-be6d36f4ecc27214-00
traceparent
的格式為version "-" version-format
,而version-format
在version
為00
的定義,又由三個部分組成trace-id "-" parent-id "-" trace-flags
實作分佈式跟踪
實作日誌紀錄
接下來的就是要將這些資訊放到日誌服務 Seq
之內,此處選擇使用 Serilog
套件
1 | # dotnet Core Serilog 套件 |
1 | // program.cs |
確認 Seq 是否有紀錄到正確資訊
開啟 frontEndApp 跟 backendApp,並透過中斷點檢視 backendApp
所接收到的 traceparent
接著到 seq
查看是否有紀錄TraceId
及SpanId
使用 zipkin 檢視 tracing 紀錄
安裝 nuget 套件(照著套件名稱搜尋,並勾選 prerelease
)
1 | <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.2.0-rc5" /> |
將應用程式的資料直接透過 exporter 傳遞給 zipkin
1 | // program.cs |
appsetting.json
裡面的ServiceName
是提供給 zipkin 顯示的服務名稱
1 | //appsetting.json |