.NET运行时中的监测和可观测性
今年5月份的時候研究分布式追蹤的問題知道了的攔截方式比較零散, 剛好8月份的時候看到這篇文章,這個文章總結(jié)的比較完整。存檔了很久,趁今天有空翻譯給大家。原文地址,校驗:張蘅水
.NET是一個托管運(yùn)行時,這意味著它提供了“管理”您的程序的高級功能,從簡介到公共語言運(yùn)行時(CLR)(2007年編寫):
運(yùn)行時具有許多功能,因此按如下方式對它們進(jìn)行分類很有用:
基本功能?對其他功能設(shè)計有廣泛影響的功能。這些包括:
1.垃圾收集
2.記憶安全和類型安全
3.對編程語言的高級支持。
輔助功能?- 許多有用的程序可能不需要基本特性所支持的功能:
1.使用AppDomains進(jìn)行程序隔離
2.程序安全和沙盒
其他功能?- 所有運(yùn)行時環(huán)境都需要但不利用CLR基本功能的功能。相反,它們是創(chuàng)建完整編程環(huán)境的結(jié)果。其中包括:
1.版本
2.Debugging/Profiling
3.互操作
您可以看到,“Debugging/Profiling”雖然不是基本或輔助功能,但由于“ 需要創(chuàng)建完整的編程環(huán)境 ” ,它仍然會進(jìn)入列表。
這篇文章的其余部分將看什么?監(jiān)測,可觀測性和內(nèi)省功能核心CLR提供,為什么他們是有用的,如何提供他們。
為了便于瀏覽,帖子分為3個主要部分(最后有一些“額外閱讀材料”):
診斷(Diagnostics)
Perf View(性能分析工具)
共同基礎(chǔ)設(shè)施
未來的計劃
剖析(Profiling)
ICorProfiler API
分析 v .調(diào)試
調(diào)試(Debugging)
ICorDebug API
SOS和DAC
第三方調(diào)試器
記憶轉(zhuǎn)儲
0|1診斷(Diagnostics)
首先,我們將查看CLR提供的診斷信息,傳統(tǒng)上這些信息是通過“Windows事件跟蹤”(ETW)提供的。
CLR提供的各種事件涉及:
垃圾收集(GC)
即時(JIT)編譯
模塊和AppDomains
線程和鎖爭用
以及更多
例如,這是觸發(fā)AppDomain Load事件的地方,這是Exception Thrown事件,這里是GC Allocation Tick事件。
Perf View
如果你想看到來自你的.NET程序的ETW事件,我建議使用優(yōu)秀的PerfView工具,從這些PerfView教程開始,或者這個優(yōu)秀的演講PerfView:終極.NET性能工具。PerfView被廣泛認(rèn)可,因為它提供了寶貴的信息,例如Microsoft工程師經(jīng)常將其用于性能調(diào)查。
共同基礎(chǔ)設(shè)施
但是,如果從名稱中不清楚,ETW事件僅在Windows上可用,這并不適合新的.NET“跨平臺”世界。您可以在Linux上使用PerfView進(jìn)行性能跟蹤(通過LTTng),但這只是cmd-line集合工具,稱為“PerfCollect”,分析和豐富的UI(包括flamegraphs)目前僅適用于Windows。
但是如果你想分析.NET Performance Linux,還有其他一些方法:
在Linux上使用.NET Core獲取LTTng事件的堆棧
Linux性能問題
上面的第二個鏈接討論了在.NET Core中正在使用的新“EventPipe”基礎(chǔ)架構(gòu)(以及EventSources和EventListeners,你能發(fā)現(xiàn)一個主題!),你可以看到它在跨平臺性能監(jiān)控設(shè)計中的目標(biāo)。在高層次上,它將為CLR提供一個單獨(dú)的位置來推動與診斷和性能相關(guān)的“事件”。然后,這些“事件”將被路由到一個或多個記錄器,例如,可能包括ETW,LTTng和BPF,精確記錄器由CLR運(yùn)行的OS /平臺確定。.NET Cross-Plat性能和事件設(shè)計中還有更多背景信息可以解釋不同日志記錄技術(shù)的優(yōu)缺點(diǎn)。
“事件管道”中正在進(jìn)行的所有工作都在“性能監(jiān)控”項目和相關(guān)的“EventPipe”問題中進(jìn)行跟蹤。
未來的計劃
最后,還有一個性能分析控制器的(Performance Profiling Controller?)未來計劃,其目標(biāo)如下:
控制器負(fù)責(zé)以簡單和跨平臺的方式控制性能分析基礎(chǔ)結(jié)構(gòu)和.NET性能診斷組件生成的性能數(shù)據(jù)。
我們的想法是通過從“事件管道”中提取所有相關(guān)數(shù)據(jù),通過HTTP服務(wù)器公開以下功能:
REST API
Pri 1:簡單分析:為運(yùn)行時間配置X個時間并返回跟蹤。
Pri 1:高級分析:開始跟蹤(以及配置)
Pri 1:高級分析:停止跟蹤(對此調(diào)用的響應(yīng)將是跟蹤本身)
Pri 2:獲取與所有EventCounters或指定EventCounter相關(guān)的統(tǒng)計信息。
可瀏覽的HTML頁面
Pri 1:流程中所有托管代碼堆棧的文本表示。
提供當(dāng)前正在運(yùn)行的用作簡單診斷報告的快照概述。
Pri 2:顯示EventCounters的當(dāng)前狀態(tài)(可能具有歷史記錄)。
* 提供現(xiàn)有計數(shù)器及其值的概述。
* 開放性問題:我不相信存在必要的公共API來枚舉EventCounters。
我很高興看到“性能分析控制器(Performance Profiling Controller)”(PPC?)的位置,我認(rèn)為將這種內(nèi)置到CLR中確實(shí)非常有價值,這是其他運(yùn)行時的內(nèi)容。
0|1剖析(Profiling)
CLR提供的另一個強(qiáng)大功能是Profiling API,它(大部分)被第三方工具用于在非常低級別掛鉤到運(yùn)行時。您可以在此概述中找到有關(guān)API的更多信息,但在較高級別,它允許您連接在以下情況下觸發(fā)的回調(diào):
GC相關(guān)事件發(fā)生
拋出異常
裝配/卸載裝配
更多,更多
來自BOTR頁面的圖像分析API - 概述
此外還有其他非常強(qiáng)大的功能。首先,您可以設(shè)置每次執(zhí)行.NET方法時調(diào)用的掛鉤,無論是在運(yùn)行時還是用戶代碼中。這些回調(diào)被稱為“進(jìn)入/離開”鉤子,并且有一個很好的示例顯示如何使用它們,但為了使它們工作,您需要了解不同操作系統(tǒng)和CPU架構(gòu)的“調(diào)用約定”,這并不總是容易的。另外,作為警告,Profiling API是一個只能通過C / C ++代碼訪問的COM組件,你不能在C#/ F#/ VB.NET中使用它!
其次,Profiler能夠通過SetILFunctionBody()API在JIT?之前重寫任何.NET方法的IL代碼。這個API功能非常強(qiáng)大,構(gòu)成了許多.NET?APM工具的基礎(chǔ),您可以在我之前的文章中了解更多關(guān)于如何使用它的方法。如何模擬密封類和靜態(tài)方法以及隨附的代碼。
ICorProfiler API
事實(shí)證明,運(yùn)行時必須執(zhí)行各種瘋狂的技巧才能使Profiling API正常工作,只需查看進(jìn)入此PR的內(nèi)容允許重新連接(有關(guān)'ReJIT'的詳細(xì)信息,請參閱ReJIT:A How-To指南)。
所有Profiling API接口和回調(diào)的總體定義可在\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.這在以下文件中實(shí)現(xiàn):
\VM\proftoeeinterfaceimpl.h
\VM\proftoeeinterfaceimpl.inl
\VM\proftoeeinterfaceimpl.cpp
另一個主要部分是EE - > Profiler回調(diào),它們在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.這些回調(diào)在以下文件中實(shí)現(xiàn):
VM\eetoprofinterfaceimpl.h
VM\eetoprofinterfaceimpl.inl
VM\eetoprofinterfaceimpl.cpp
VM\eetoprofinterfacewrapper.inl
最后,值得指出的是,Profiler API可能無法在.NET Core運(yùn)行的所有操作系統(tǒng)和CPU-arch上運(yùn)行,例如Linux上的ELT調(diào)用存根問題,有關(guān)詳細(xì)信息,請參閱CoreCLR Profiler API的狀態(tài)。
分析和調(diào)試(Profiling v. Debugging)
除此之外,“分析”和“調(diào)試”確實(shí)有一些重疊,因此從CLR調(diào)試與CLR分析中了解.NET運(yùn)行時上下文中不同的API提供了什么是有幫助的。
0|1調(diào)試(Debugging)
調(diào)試意味著不同的事情不同的人,比如我問在Twitter上“?什么是你調(diào)試的.NET程序的途徑?”,并得到了廣泛的不同反應(yīng),雖然反應(yīng)兩組含有一個很好的工具清單和技術(shù),所以他們值得一試,謝謝#LazyWeb!
但也許這句話最好總結(jié)一下Debugging究竟是什么?
CLR提供了與調(diào)試相關(guān)的非常廣泛的功能,但為什么需要提供這些服務(wù),優(yōu)秀的帖子為什么托管調(diào)試與本機(jī)調(diào)試不同?提供了3個理由:
可以在硬件級別抽象本機(jī)調(diào)試,但需要在IL級別抽象管理調(diào)試
托管調(diào)試需要大量的信息,直到運(yùn)行時才可用
托管調(diào)試器需要與垃圾收集器(GC)協(xié)調(diào)
所以給一個體面的經(jīng)驗,CLR?具有提供更高級別的調(diào)試API稱ICorDebug,這將在下面從“常用的調(diào)試方案”的圖像中顯示的BOTR:
此外,還有很好的描述了不同部分如何在管理斷點(diǎn)如何工作中相互作用?,雖然描述左和右是上圖中的相反!
Here’s an overview of the pipeline of components:1) End-user2) 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 5) Debuggee's code (such as end users C# program)ICorDebug API
但是如何實(shí)現(xiàn)所有這些以及從CLR Debugging簡要介紹的不同組件是什么:
所有.Net調(diào)試支持都在我們稱之為“The Dac”的dll之上實(shí)現(xiàn)。此文件(通常命名mscordacwks.dll)是我們的公共調(diào)試API(ICorDebug)以及兩個私有調(diào)試API?的構(gòu)建塊:SOS-Dac API和IXCLR。
在一個完美的世界中,每個人都會使用ICorDebug我們的公共調(diào)試API。但是,像您這樣的工具開發(fā)人員所需的絕大多數(shù)功能都缺乏ICorDebug。這是我們正在修復(fù)的問題,但這些改進(jìn)將進(jìn)入CLR v.next,而不是舊版本的CLR。實(shí)際上,ICorDebugAPI僅在CLR v4中添加了對故障轉(zhuǎn)儲調(diào)試的支持。任何調(diào)試CLR v2崩潰轉(zhuǎn)儲的人根本無法使用ICorDebug!
(有關(guān)其他文章,請參閱SOS和ICorDebug)
該ICorDebugAPI實(shí)際上是分成多個接口,也有在他們的70!我不會在這里列出所有內(nèi)容,但是我將展示它們所屬的類別,有關(guān)更多信息,請參閱ICorDebug的分區(qū),其中包含此列表,因為它更詳細(xì)。
頂級(Debugging):?ICorDebug + ICorDebug2是頂級接口,有效地充當(dāng)ICorDebugProcess對象的集合。
回調(diào)(Callbacks):通過調(diào)試器實(shí)現(xiàn)的回調(diào)對象上的方法調(diào)度托管調(diào)試事件
進(jìn)程(Process):這組接口表示正在運(yùn)行的代碼,并包含與事件相關(guān)的API。
代碼/類型檢查(Code / Type Inspection):?主要可以在靜態(tài)PE映像上運(yùn)行,但實(shí)時數(shù)據(jù)有一些便捷方法。
執(zhí)行控制(Execution Control):執(zhí)行是“檢查”線程執(zhí)行的能力。實(shí)際上,這意味著放置斷點(diǎn)(F9)和踩踏(F11步入,F10步進(jìn),S + F11步出)等。ICorDebug的執(zhí)行控制僅在托管代碼中運(yùn)行。
線程+調(diào)用堆棧(Threads + Callstacks):調(diào)用堆棧是調(diào)試器檢查功能的支柱。以下接口與獲取callstack有關(guān)。ICorDebug僅公開調(diào)試托管代碼,因此堆棧跟蹤僅受管理。
對象檢查(Object Inspection):對象檢查是API的一部分,它允許您在整個調(diào)試對象中查看變量的值。對于每個接口,我列出了“MVP”方法,我認(rèn)為必須簡潔地傳達(dá)該接口的用途。
另外需要注意的是,與Profiling APIs一樣,調(diào)試API的支持級別因操作系統(tǒng)和CPU架構(gòu)而異。例如,截至2018年8月,“沒有針對Linux ARM進(jìn)行托管調(diào)試和診斷的解決方案”。有關(guān)“Linux”支持的更多信息,請參閱這篇很棒的文章,在Linux上使用LLDB調(diào)試.NET Core,并從Microsoft?檢出診斷存儲庫,其目標(biāo)是更容易在Linux上調(diào)試.NET程序。
最后,如果你想看看ICorDebugAPI在C#中的樣子,看一下CLRMD庫中包含的包裝器,包括所有可用的回調(diào)(CLRMD將在后面的文章中進(jìn)行更深入的介紹)。
SOS和DAC
“數(shù)據(jù)訪問組件(Data Access Component)”(DAC)在BOTR頁面中有詳細(xì)討論,但實(shí)際上它提供了對CLR數(shù)據(jù)結(jié)構(gòu)的“進(jìn)程外”訪問,因此可以從另一個進(jìn)程讀取其內(nèi)部詳細(xì)信息。這允許調(diào)試器(via?ICorDebug)或'Son of Strike'(SOS)擴(kuò)展進(jìn)入CLR的運(yùn)行實(shí)例或內(nèi)存轉(zhuǎn)儲,并找到如下內(nèi)容:
所有正在運(yùn)行的線程
托管堆上有哪些對象
有關(guān)方法的完整信息,包括機(jī)器代碼
當(dāng)前的'堆棧跟蹤'
除此之外,如果您想要解釋所有奇怪的名稱和一點(diǎn)'.NET歷史課',請參閱此Stack Overflow答案。
SOS命令的完整列表非常令人印象深刻,并且在WinDBG旁邊使用它可以讓您非常低級地了解程序和CLR中發(fā)生的情況。要了解它是如何實(shí)現(xiàn)的,讓我們看一下這個!HeapStat命令,該命令可以為您提供.NET GC正在使用的不同堆大小的摘要:
(來自SOS的圖片:即將發(fā)布的版本有一些新命令 - HeapStat)
這是代碼流,顯示了SOS和DAC如何協(xié)同工作:
SOS完整!HeapStat命令(鏈接)
SOS!HeapStat處理'Workstation GC'?的命令中的代碼(鏈接)
SOS?GCHeapUsageStats(..)功能,重負(fù)荷(鏈接)
共享DacpGcHeapDetails包含指向GC堆中主數(shù)據(jù)的指針的數(shù)據(jù)結(jié)構(gòu),例如段,卡表和各代(鏈接)
GetGCHeapStaticData填充DacpGcHeapDetails結(jié)構(gòu)的DAC函數(shù)(鏈接)
共享DacpHeapSegmentData包含GC堆的單個“段”的詳細(xì)信息的數(shù)據(jù)結(jié)構(gòu)(鏈接)
GetHeapSegmentData(..)填充DacpHeapSegmentData結(jié)構(gòu)的DAC(鏈接)
第三方'調(diào)試器'(3rd Party ‘Debuggers’)
由于Microsoft發(fā)布了調(diào)試API,它允許第三方使用ICorDebug接口,這里列出了我遇到的一些內(nèi)容:
調(diào)試器.NET Core運(yùn)行時來自三星
調(diào)試器提供GDB / MI或VSCode調(diào)試適配器接口,并允許在.NET Core運(yùn)行時下調(diào)試.NET應(yīng)用程序。
可能是他們將.NET Core移植到他們的Tizen OS的工作的一部分
dnSpy?- “.NET調(diào)試器和匯編編輯器”
一個非常令人印象深刻的工具,它是一個'調(diào)試器','匯編編輯器','十六進(jìn)制編輯器','反編譯器'等等!
MDbg.exe(.NET Framework命令行調(diào)試程序)
可以作為NuGet包和GitHub存儲庫使用,也可以從Microsoft下載。
但是,目前MDBG似乎不適用于.NET Core,請參閱端口MDBG到CoreCLR和ETA以將mdbg移植到coreclr以獲取更多信息。
JetBrains'Rider'允許在Windows上進(jìn)行.NET Core調(diào)試
雖然由于許可問題引起了一些爭議
有關(guān)更多信息,請參閱此HackerNews主題
記憶轉(zhuǎn)儲(Memory Dumps)
我們要看的最后一個區(qū)域是“內(nèi)存轉(zhuǎn)儲”,可以從實(shí)時系統(tǒng)中捕獲并離線分析。.NET運(yùn)行時一直很好地支持在Windows上創(chuàng)建“內(nèi)存轉(zhuǎn)儲”,現(xiàn)在.NET Core是“跨平臺”,也可以在其他操作系統(tǒng)上使用相同的工具。
“內(nèi)存轉(zhuǎn)儲”的一個問題是,獲取SOS和DAC文件的正確匹配版本可能會非常棘手。幸運(yùn)的是,Microsoft剛剛發(fā)布了以下dotnet symbolCLI工具:
可以下載任何給定核心轉(zhuǎn)儲,minidump或任何支持平臺的文件格式(如ELF,MachO,Windows DLL,PDB和便攜式PDB)的調(diào)試所需的所有文件(給出coreclr模塊的符號,模塊,SOS和DAC)。
最后,如果你花費(fèi)任何時間分析'內(nèi)存轉(zhuǎn)儲',你真的應(yīng)該看看微軟幾年前發(fā)布的優(yōu)秀的CLR MD庫。我之前已經(jīng)寫過你可以用它做什么,但簡而言之,它允許你通過一個直觀的C#API與內(nèi)存轉(zhuǎn)儲交互,其中的類可以訪問ClrHeap,GC Roots,CLR Threads,Stack Frames和更多。實(shí)際上,除了實(shí)現(xiàn)工作所需的時間之外,CLR MD還可以實(shí)現(xiàn)大多數(shù)(如果不是全部)SOS命令。
但是從宣布帖子來看它是如何運(yùn)作的:
ClrMD托管庫是CLR僅內(nèi)部調(diào)試API的包裝器。雖然這些僅內(nèi)部API對于診斷非常有用,但我們不支持它們作為公開的,有文檔的版本,因為它們非常難以使用并且與CLR的其他實(shí)現(xiàn)細(xì)節(jié)緊密耦合。ClrMD通過圍繞這些低級調(diào)試API提供易于使用的托管包裝來解決此問題。
通過在官方支持的庫中提供這些API,Microsoft使開發(fā)人員能夠在CLRMD之上構(gòu)建各種工具,這是一個很好的結(jié)果!
總而言之,.NET Runtime提供了廣泛的診斷,調(diào)試和分析功能,可以深入了解CLR內(nèi)部的情況。
原文地址:https://www.cnblogs.com/WithLin/p/9798485.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的.NET运行时中的监测和可观测性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 干货!请码住——点此领取免费开源框架
- 下一篇: .NETCore 简单且高级的库 csr