.NET執行時中的監測和可觀測性
今年5月份的時候研究分散式追蹤的問題知道了的攔截方式比較零散, 剛好8月份的時候看到這篇文章,這個文章總結的比較完整。存檔了很久,趁今天有空翻譯給大家。 ofollow,noindex" target="_blank">原文地址 ,校驗:張蘅水
.NET是一個 託管執行時 ,這意味著它提供了“管理”您的程式的高階功能,從 簡介到公共語言執行時(CLR) (2007年編寫):
執行時具有許多功能,因此按如下方式對它們進行分類很有用:
- 基本功能 對其他功能設計有廣泛影響的功能。這些包括:
1.垃圾收集
2.記憶安全和型別安全
3.對程式語言的高階支援。 - 輔助功能 - 許多有用的程式可能不需要基本特性所支援的功能:
1.使用AppDomains進行程式隔離
2.程式安全和沙盒 - 其他功能 - 所有執行時環境都需要但不利用CLR基本功能的功能。相反,它們是建立完整程式設計環境的結果。其中包括:
1.版本
2. Debugging/Profiling
3.互操作
您可以看到,“ Debugging/Profiling ”雖然不是基本或輔助功能,但由於“ 需要建立完整的程式設計環境 ” ,它仍然會進入列表。
這篇文章的其餘部分將看 什麼 監測 , 可觀測性 和 內省 功能核心CLR提供, 為什麼 他們是有用的, 如何 提供他們。
為了便於瀏覽,帖子分為3個主要部分(最後有一些“額外閱讀材料”):
- 診斷(Diagnostics)
- Perf View(效能分析工具)
- 共同基礎設施
- 未來的計劃
- 剖析(Profiling)
- ICorProfiler API
- 分析 v .除錯
- 除錯(Debugging)
- ICorDebug API
- SOS和DAC
- 第三方偵錯程式
- 記憶轉儲
診斷(Diagnostics)
首先,我們將檢視CLR提供的 診斷 資訊,傳統上這些資訊是通過 “Windows事件跟蹤” (ETW)提供的。
CLR提供的 各種事件涉及:
- 垃圾收集(GC)
- 即時(JIT)編譯
- 模組和AppDomains
- 執行緒和鎖爭用
- 以及更多
例如,這是 觸發AppDomain Load事件的 地方,這是 Exception Thrown事件 ,這裡是 GC Allocation Tick事件 。
Perf View
如果你想看到來自你的.NET程式的ETW事件,我建議使用優秀的 PerfView工具 ,從這些 PerfView教程 開始,或者這個優秀的演講 PerfView:終極.NET效能工具 。PerfView被廣泛認可,因為它提供了寶貴的資訊,例如Microsoft工程師經常將其用於 效能調查 。
共同基礎設施
但是,如果從名稱中不清楚,ETW事件僅在Windows上可用,這並不適合新的.NET“跨平臺”世界。您可以 在Linux上 使用 PerfView進行效能跟蹤 (通過 LTTng ),但這只是cmd-line集合工具,稱為“PerfCollect”,分析和豐富的UI(包括 flamegraphs )目前僅適用於Windows。
但是如果你想分析.NET Performance Linux,還有其他一些方法:
上面的第二個連結討論了在.NET Core中正在使用的新 “EventPipe”基礎架構 (以及EventSources和EventListeners,你能發現一個主題!),你可以看到它在 跨平臺效能監控設計中的目標 。在高層次上,它將為CLR提供一個單獨的位置來推動與診斷和效能相關的“事件”。然後,這些“事件”將被路由到一個或多個記錄器,例如,可能包括ETW,LTTng和BPF,精確記錄器由CLR執行的OS /平臺確定。 .NET Cross-Plat效能和事件設計 中還有更多背景資訊可以解釋不同日誌記錄技術的優缺點。
“事件管道”中正在進行的所有工作都在 “效能監控”專案 和相關的 “EventPipe”問題中 進行跟蹤。
未來的計劃
最後,還有一個 效能分析控制器的(Performance Profiling Controller ) 未來計劃,其目標如下:
控制器負責以簡單和跨平臺的方式控制性能分析基礎結構和.NET效能診斷元件生成的效能資料。
我們的想法是 通過 從“事件管道”中提取所有相關資料,通過 HTTP伺服器 公開 以下功能 :
REST API
- Pri 1:簡單分析:為執行時間配置X個時間並返回跟蹤。
- Pri 1:高階分析:開始跟蹤(以及配置)
- Pri 1:高階分析:停止跟蹤(對此呼叫的響應將是跟蹤本身)
- Pri 2:獲取與所有EventCounters或指定EventCounter相關的統計資訊。
可瀏覽的HTML頁面
- Pri 1:流程中所有託管程式碼堆疊的文字表示。
- 提供當前正在執行的用作簡單診斷報告的快照概述。
- Pri 2:顯示EventCounters的當前狀態(可能具有歷史記錄)。
* 提供現有計數器及其值的概述。
* 開放性問題:我不相信存在必要的公共API來列舉EventCounters。
我很高興看到“ 效能分析控制器(Performance Profiling Controller) ”(PPC?)的位置,我認為將這種內建到CLR中確實非常有價值,這是 其他執行時的內容 。
剖析(Profiling)
CLR提供的另一個強大功能是 Profiling API ,它(大部分)被第三方工具用於在非常低級別掛鉤到執行時。您可以在 此概述中 找到有關API的更多資訊,但在較高級別,它允許您連線在以下情況下觸發的回撥:
- GC相關事件發生
- 丟擲異常
- 裝配/解除安裝裝配
- 更多,更多
來自BOTR頁面的影象 分析API - 概述
此外還有其他 非常強大的功能 。首先,您可以 設定每次執行.NET方法時呼叫的掛鉤, 無論是在執行時還是使用者程式碼中。這些回撥被稱為“進入/離開”鉤子,並且有一個 很好的示例 顯示如何使用它們,但為了使它們工作,您需要了解 不同作業系統和CPU架構的“呼叫約定” ,這 並不總是容易的 。另外,作為警告,Profiling API是一個只能通過C / C ++程式碼訪問的COM元件,你不能在C#/ F#/ VB.NET中使用它!
其次,Profiler能夠通過 SetILFunctionBody()API 在 JIT 之前重寫任何.NET方法的IL程式碼 。這個API功能非常強大,構成了許多.NET APM工具 的基礎,您可以在我之前的文章中瞭解更多關於如何使用它的方法。 如何模擬密封類和靜態方法 以及 隨附的程式碼 。
ICorProfiler API
事實證明,執行時必須執行各種瘋狂的技巧才能使Profiling API正常工作,只需檢視進入此PR的內容 允許重新連線 (有關'ReJIT'的詳細資訊,請參閱 ReJIT:A How-To指南 )。
所有Profiling API介面和回撥的總體定義可在 \vm\inc\corprof.idl中找到 (請參閱 介面說明語言 )。但它分為2個邏輯部分,一個是 Profiler - >'Execution Engine'(EE) 介面,稱為 ICorProfilerInfo
:
// Declaration of class that implements the ICorProfilerInfo* interfaces, which allow the // Profiler to communicate with the EE.This allows the Profiler DLL to get // access to private EE data structures and other things that should never be exported // outside of the EE.
這在以下檔案中實現:
另一個主要部分是 EE - > Profiler 回撥,它們在 ICorProfilerCallback
介面下組合在一起:
// This module implements wrappers around calling the profiler's // ICorProfilerCallaback* interfaces. When code in the EE needs to call the // profiler, it goes through EEToProfInterfaceImpl to do so.
這些回撥在以下檔案中實現:
- VM\eetoprofinterfaceimpl.h
- VM\eetoprofinterfaceimpl.inl
- VM\eetoprofinterfaceimpl.cpp
- VM\eetoprofinterfacewrapper.inl
最後,值得指出的是,Profiler API可能無法在.NET Core執行的所有作業系統和CPU-arch上執行,例如 Linux上的ELT呼叫存根問題 ,有關詳細資訊,請參閱 CoreCLR Profiler API的狀態 。
分析和除錯(Profiling v. Debugging)
除此之外,“分析”和“除錯”確實有一些重疊,因此從 CLR除錯與CLR分析 中瞭解.NET執行時上下文中 不同的API提供 了 什麼是有幫助的。
除錯(Debugging)
除錯意味著不同的事情不同的人,比如我問在Twitter上“ 什麼是你除錯的.NET程式的途徑 ”,並得到了 廣泛 的 不同反應 ,雖然反應兩組含有一個很好的工具清單和技術,所以他們值得一試,謝謝#LazyWeb!
但也許這句話最好總結一下 Debugging究竟是 什麼:blush:
CLR提供了與除錯相關的非常廣泛的功能,但為什麼需要提供這些服務,優秀的帖子 為什麼託管除錯與本機除錯不同? 提供了3個理由:
- 可以在硬體級別抽象本機除錯,但 需要在IL級別抽象管理除錯
- 託管除錯需要大量的資訊, 直到執行時才可用
- 託管偵錯程式需要 與垃圾收集器(GC)協調
所以給一個體面的經驗,CLR 具有 提供 更高級別的除錯API 稱 ICorDebug
,這將在下面從“常用的除錯方案”的影象中顯示 的BOTR :
此外,還有很好的描述了不同部分 如何在管理斷點如何工作中 相互作用 ? ,雖然描述 左 和 右 是上圖中的相反!
Here’s an overview of the pipeline of components: 1) End-user 2) Debugger (such as Visual Studio or MDbg). 3) CLR Debugging Services (which we call "The Right Side"). This is the implementation of ICorDebug (in mscordbi.dll). ---- process boundary between Debugger and Debuggee ---- 4) CLR. This is mscorwks.dll. This contains the in-process portion of the debugging services (which we call "The Left Side") which communicates directly with the RS in stage #3. 5) Debuggee's code (such as end users C# program)
ICorDebug API
但是如何實現所有這些以及從 CLR Debugging簡要介紹 的不同元件是什麼:
所有.Net除錯支援都在我們稱之為“The Dac”的dll之上實現。此檔案(通常命名 mscordacwks.dll
)是我們的公共除錯API( ICorDebug
)以及兩個私有除錯API 的構建塊:SOS-Dac API和IXCLR。
在一個完美的世界中,每個人都會使用 ICorDebug
我們的公共除錯API。但是,像您這樣的工具開發人員所需的絕大多數功能都缺乏 ICorDebug
。這是我們正在修復的問題,但這些改進將進入CLR v.next,而不是舊版本的CLR。實際上, ICorDebug
API僅在CLR v4中添加了對故障轉儲除錯的支援。任何除錯CLR v2崩潰轉儲的人根本無法使用 ICorDebug
!
(有關其他文章,請參閱 SOS和ICorDebug )
該 ICorDebug
API實際上是分成多個介面,也有在他們的70!我不會在這裡列出所有內容,但是我將展示它們所屬的類別,有關更多資訊,請參閱 ICorDebug的分割槽, 其中包含此列表,因為它更詳細。
- 頂級(Debugging): ICorDebug + ICorDebug2是頂級介面,有效地充當ICorDebugProcess物件的集合。
- 回撥(Callbacks): 通過偵錯程式實現的回撥物件上的方法排程託管除錯事件
- 程序(Process): 這組介面表示正在執行的程式碼,幷包含與事件相關的API。
- 程式碼/型別檢查(Code / Type Inspection): 主要可以在靜態PE映像上執行,但實時資料有一些便捷方法。
- 執行控制(Execution Control): 執行是“檢查”執行緒執行的能力。實際上,這意味著放置斷點(F9)和踩踏(F11步入,F10步進,S + F11步出)等。ICorDebug的執行控制僅在託管程式碼中執行。
- 執行緒+呼叫堆疊(Threads + Callstacks): 呼叫堆疊是偵錯程式檢查功能的支柱。以下介面與獲取callstack有關。ICorDebug僅公開除錯託管程式碼,因此堆疊跟蹤僅受管理。
- 物件檢查(Object Inspection): 物件檢查是API的一部分,它允許您在整個除錯物件中檢視變數的值。對於每個介面,我列出了“MVP”方法,我認為必須簡潔地傳達該介面的用途。
另外需要注意的是,與Profiling APIs一樣,除錯API的支援級別因作業系統和CPU架構而異。例如,截至2018年8月, “沒有針對Linux ARM進行託管除錯和診斷的解決方案” 。有關“Linux”支援的更多資訊,請參閱這篇很棒的文章, 在Linux上使用LLDB除錯.NET Core, 並從Microsoft 檢出 診斷儲存庫 ,其目標是更容易在Linux上除錯.NET程式。
最後,如果你想看看 ICorDebug
API在C#中的樣子,看一下 CLRMD庫中包含 的 包裝器 ,包括所有 可用的回撥 (CLRMD將在後面的文章中進行更深入的介紹)。
SOS和DAC
“資料訪問元件(Data Access Component)”(DAC)在 BOTR頁面 中有詳細討論,但實際上它提供了對CLR資料結構的“程序外”訪問,因此可以從 另一個程序 讀取其內部詳細資訊。這允許偵錯程式(via ICorDebug
)或 'Son of Strike'(SOS)擴充套件 進入CLR的執行例項或記憶體轉儲,並找到如下內容:
- 所有正在執行的執行緒
- 託管堆上有哪些物件
- 有關方法的完整資訊,包括機器程式碼
- 當前的'堆疊跟蹤'
除此之外,如果您想要解釋所有奇怪的名稱和一點'.NET歷史課',請參閱 此Stack Overflow答案 。
SOS命令 的完整列表非常令人印象深刻,並且在WinDBG旁邊使用它可以讓您非常低階地瞭解程式和CLR中發生的情況。要了解它是如何實現的,讓我們看一下這個 !HeapStat
命令,該命令可以為您提供.NET GC正在使用的不同堆大小的摘要:
(來自 SOS的 圖片 :即將釋出的版本有一些新命令 - HeapStat )
這是程式碼流,顯示了SOS和DAC如何協同工作:
- SOS 完整
!HeapStat
命令( 連結 ) - SOS
!HeapStat
處理'Workstation GC' 的命令中的程式碼( 連結 ) - SOS
GCHeapUsageStats(..)
功能,重負荷( 連結 ) - 共享
DacpGcHeapDetails
包含指向GC堆中主資料的指標的資料結構,例如段,卡表和各代( 連結 ) -
GetGCHeapStaticData
填充DacpGcHeapDetails
結構的 DAC 函式( 連結 ) - 共享
DacpHeapSegmentData
包含GC堆的單個“段”的詳細資訊的資料結構( 連結 ) -
GetHeapSegmentData(..)
填充DacpHeapSegmentData
結構的 DAC ( 連結 )
第三方'偵錯程式'(3rd Party ‘Debuggers’)
由於Microsoft釋出了除錯API,它允許第三方使用 ICorDebug
介面,這裡列出了我遇到的一些內容:
- 偵錯程式.NET Core執行時 來自 三星
- 偵錯程式提供GDB / MI或VSCode除錯介面卡介面,並允許在.NET Core執行時下除錯.NET應用程式。
- 可能 是他們 將.NET Core移植到他們的Tizen OS 的工作的一部分
- dnSpy - “.NET偵錯程式和彙編編輯器”
- 一個 非常 令人印象深刻的工具 ,它是一個'偵錯程式','彙編編輯器','十六進位制編輯器','反編譯器'等等!
- MDbg.exe(.NET Framework命令列除錯程式)
- 可以作為 NuGet包 和 GitHub儲存庫使用 ,也可以 從Microsoft下載 。
- 但是,目前MDBG似乎不適用於.NET Core,請參閱 埠MDBG到CoreCLR 和 ETA以將mdbg移植到coreclr 以獲取更多資訊。
- JetBrains'Rider' 允許在Windows上進行.NET Core除錯
- 雖然由於許可問題引起了 一些爭議
- 有關更多資訊,請參閱 此HackerNews主題
記憶轉儲(Memory Dumps)
我們要看的最後一個區域是“記憶體轉儲”,可以從 實時 系統中捕獲並離線分析。.NET執行時一直很好地支援 在Windows上建立“記憶體轉儲” ,現在.NET Core是“跨平臺”,也可以 在其他作業系統上使用相同的 工具。
“記憶體轉儲”的一個問題是,獲取SOS和DAC檔案的正確匹配版本可能會非常棘手。幸運的是,Microsoft剛剛釋出了以下 dotnet symbol
CLI工具 :
可以下載任何給定核心轉儲,minidump或任何支援平臺的檔案格式(如ELF,MachO,Windows DLL,PDB和行動式PDB)的除錯所需的所有檔案(給出coreclr模組的符號,模組,SOS和DAC)。
最後,如果你花費任何時間 分析'記憶體轉儲', 你真的應該看看微軟幾年前釋出的優秀的 CLR MD庫 。我之前 已經寫過 你可以用它做什麼,但簡而言之,它允許你通過一個直觀的C#API與記憶體轉儲互動,其中的類可以訪問 ClrHeap , GC Roots , CLR Threads , Stack Frames 和 更多 。實際上,除了實現工作所需的時間之外,CLR MD還可以 實現 大多數 (如果不是全部)SOS命令 。
ClrMD託管庫是CLR僅內部除錯API的包裝器。雖然這些僅內部API對於診斷非常有用,但我們不支援它們作為公開的,有文件的版本,因為它們非常難以使用並且與CLR的其他實現細節緊密耦合。ClrMD通過圍繞這些低階除錯API提供易於使用的託管包裝來解決此問題。
通過在官方支援的庫中提供這些API,Microsoft使開發人員能夠在CLRMD之上構建 各種工具 ,這是一個很好的結果!