背景
隨着支撐的內部業務系統越來越多,向着服務化架構進化,在整個迭代過程中,會逐漸暴露出以下問題。
- 傳統依賴於應用服務器日志等手段的排除故障原因的復雜度越來越高,傳統的監控服務已經無法滿足需求。
終端--> Nginx --> IIS --> Asp.net 管道 --> [數據緩存]->[HTTP調用]->[DB讀寫] 在以上調用鏈路上,我們以往勉強能從 Nginx 日志中分析出 客戶端調用時長,Nginx 調用API服務時長。 但是到了應用程序代碼,對於[數據緩存]->[HTTP調用]->[DB讀寫]等操作,變成了鏈路調用黑盒。
- 在出現性能問題定位,也嚴重依賴高級工程師經驗,定位困難,指標不明確。
- 在分析整個應用調用鏈路,不能清晰、直觀的分析展現。
度量(Metrics),跟蹤(Tracing),日志(Logging)
Logging,Metrics 和 Tracing 有各自專注的部分。
- Logging - 用於記錄離散的事件。例如,應用程序的調試信息或錯誤信息。它是我們診斷問題的依據。
- Metrics - 用於記錄可聚合的數據。例如,隊列的當前深度可被定義為一個度量值,在元素入隊或出隊時被更新;HTTP 請求個數可被定義為一個計數器,新請求到來時進行累加。
- Tracing - 用於記錄請求范圍內的信息。例如,一次遠程方法調用的執行過程和耗時。它是我們排查系統性能問題的利器。

詳細閱讀,參考度量(Metrics),跟蹤(Tracing),日志(Logging)
這三者的交集,才是對於我們分析應用程序運行狀態及調用鏈路分析,有這直觀重要的意義。
日志(Logging),可以使用ELK技術棧,解決我們的應用程序日志查詢分析的大部分需求。
度量(Metrics),可以使用AppMetrics 和 Prometheus 來滿足一部分需求。
跟蹤(Tracing),全鏈路的調用分析追蹤,目前解決方案大部分也是商業解決方案,如Application Insights、OneAPM、聽雲、Datadog等,開源方案,如SkyAPM (.net core適用)
目前,針對 .net 平台下探針的解決方案進行調研,大部分是付費,開源方案大部分針對 .net core。
有沒有一種可能,我們使用開源技術,搭建自己的全鏈路調用分析的解決方案,這是本篇博文需要探索的議題。
我們將帶着以下幾個問題,進行探索解決方案
- 我們基於什么標准規范來收集指標?
- 出於保護企業現有投資的情況下,我們需要針對Full Framework(.net Framework、.net core)下進行支持,也可以考慮公有雲應用監控。
- 代碼級定位性能問題
- 記錄應用錯誤過程
- 檢測慢SQL語句
- 檢測外部調用API耗時
- 檢測調用外部HTTP請求耗時,請求信息記錄
- 請求/RPC 調用關系拓撲
- 基於什么架構來搭建,有哪些組件可用,能不能達到商業解決方案的相差無幾的解決方案?
- 用什么的技術來實現?
跟蹤(Tracing)標准 OpenTracking
OpenTracking 為監測提供了一組標准的框架無關、廠商無關的標准規范,這意味着開發者能夠很方便的添加/切換跟蹤系統
簡單說,OpenTracking 提供了一組規范,也是分布式跟蹤系統的標准的抽象,來解決不同的分布式追蹤系統的API標准的不兼容問題。OpenTracing 是一個輕量級的標准化層,它位於應用程序/類庫和追蹤或日志分析程序之間。
更多關於 OpenTracing 數據模型的知識,請參考 OpenTracing語義標准。
技術探索
分布式追蹤系統,由追蹤器(Tracker)、追蹤信息收集代理(Agent)、追蹤信息存儲分析服務(APM Server)組成。
追蹤器(Tracker):負責應用程序監控(代碼級別執行時間、異常調用)
追蹤信息收集代理(Agent):負責應用程序監控信息上報
追蹤信息存儲分析服務(APM Server):負責存儲應用程序監控信息存儲分析展示等服務
追蹤器(Tracker)
代碼埋點是實現Tracker重要一步。
如果在業務代碼中實現追蹤埋點,不但工程量大,而且代碼入侵嚴重。
var tracker = Tracker.Instance;
using(var context = tracker.Begin())
{
context.SetSpan("name of span");
/// some business logic
context.EndSpan();
tracker.Send(context);
}
為了實現dotnet全平台下(Framework、dotcore)追蹤,我們需要清楚C#代碼是如何變成機器可運行的代碼。
- 第一步,C# 編譯生成中間語言 IL
- 第二步,中間語言IL 通過CLR的即時編譯JIT,編譯成Native Code
我們只能通過,在CLR即時編譯 IL之前,修改已生成的IL,來實現代碼埋點。這樣以來,我們便可以輕松的實現零入侵業務代碼。
如何實現修改已生成的IL ? 我們通過實現CLR公共語言運行時ICorProfilerCallback 中重寫JITCompilationStarted 方法即可實現。
在dotnet core 下通過DiagnosticSource 實現,應用程序性能診斷
DiagnosticSource VS EventSource
- EventSource,只支持Windows,主要記錄可序列化的數據,被進程意外的消費。
- DiagnosticSource,支持 .net core下,主要在進程內處理數據,可以支持非序列化的對象,比如HttpConext,HttpResponse。
- 如果在 EventSource 中獲取 DiagnosticSource 中的事件數據,可以通過 DiagnosticSourceEventSource 這個對象來進行數據橋接。
