.NET運行時中的監測和可觀測性

今年5月份的時候研究分佈式追蹤的問題知道了的攔截方式比較零散, 恰好8月份的時候看到這篇文章,這個文章總結的比較完整。存檔了好久,趁今天有空翻譯給你們。原文地址,校驗:張蘅水linux

.NET是一個託管運行時,這意味着它提供了「管理」您的程序的高級功能,從簡介到公共語言運行時(CLR)(2007年編寫):git

運行時具備許多功能,所以按以下方式對它們進行分類頗有用:github

  1. 基本功能 對其餘功能設計有普遍影響的功能。這些包括:
    1.垃圾收集
    2.記憶安全和類型安全
    3.對編程語言的高級支持。
  2. 輔助功能 - 許多有用的程序可能不須要基本特性所支持的功能:
    1.使用AppDomains進行程序隔離
    2.程序安全和沙盒
  3. 其餘功能 - 全部運行時環境都須要但不利用CLR基本功能的功能。相反,它們是建立完整編程環境的結果。其中包括:
    1.版本
    2.Debugging/Profiling
    3.互操做

您能夠看到,「Debugging/Profiling」雖然不是基本或輔助功能,但因爲「 須要建立完整的編程環境 」 ,它仍然會進入列表。golang

這篇文章的其他部分將看什麼 監測可觀測性內省功能核心CLR提供,爲何他們是有用的,如何提供他們。編程

爲了便於瀏覽,帖子分爲3個主要部分(最後有一些「額外閱讀材料」):windows

診斷(Diagnostics)

首先,咱們將查看CLR提供的診斷信息,傳統上這些信息是經過「Windows事件跟蹤」(ETW)提供的。api

CLR提供的各類事件涉及:安全

  • 垃圾收集(GC)
  • 即時(JIT)編譯
  • 模塊和AppDomains
  • 線程和鎖爭用
  • 以及更多

例如,這是觸發AppDomain Load事件的地方,這是Exception Thrown事件,這裏是GC Allocation Tick事件服務器

Perf View

若是你想看到來自你的.NET程序的ETW事件,我建議使用優秀的PerfView工具,從這些PerfView教程開始,或者這個優秀的演講PerfView:終極.NET性能工具。PerfView被普遍承認,由於它提供了寶貴的信息,例如Microsoft工程師常常將其用於性能調查數據結構

image.png

共同基礎設施

可是,若是從名稱中不清楚,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的更多信息,但在較高級別,它容許您鏈接在如下狀況下觸發的回調:

image.png

來自BOTR頁面的圖像分析API - 概述

此外還有其餘很是強大的功能。首先,您能夠設置每次執行.NET方法時調用的掛鉤,不管是在運行時仍是用戶代碼中。這些回調被稱爲「進入/離開」鉤子,而且有一個很好的示例顯示如何使用它們,但爲了使它們工做,您須要瞭解不一樣操做系統和CPU架構的「調用約定」,這並不老是容易的。另外,做爲警告,Profiling API是一個只能經過C / C ++代碼訪問的COM組件,你不能在C#/ F#/ VB.NET中使用它!

其次,Profiler可以經過SetILFunctionBody()APIJIT 以前重寫任何.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.

這些回調在如下文件中實現:

最後,值得指出的是,Profiler API可能沒法在.NET Core運行的全部操做系統和CPU-arch上運行,例如Linux上的ELT調用存根問題,有關詳細信息,請參閱CoreCLR Profiler API的狀態

分析和調試(Profiling v. Debugging)

除此以外,「分析」和「調試」確實有一些重疊,所以從CLR調試與CLR分析中瞭解.NET運行時上下文中不一樣的API提供什麼是有幫助的。

image.png

調試(Debugging)

調試意味着不一樣的事情不一樣的人,好比我問在Twitter上「 什麼是你調試的.NET程序的途徑 」,並獲得了普遍不一樣反應,雖然反應兩組含有一個很好的工具清單和技術,因此他們值得一試,謝謝#LazyWeb!

但也許這句話最好總結一下Debugging到底是什麼😊

image.png

CLR提供了與調試相關的很是普遍的功能,但爲何須要提供這些服務,優秀的帖子爲何託管調試與本機調試不一樣?提供了3個理由:

  1. 能夠在硬件級別抽象本機調試,但須要在IL級別抽象管理調試
  2. 託管調試須要大量的信息,直到運行時纔可用
  3. 託管調試器須要與垃圾收集器(GC)協調

因此給一個體面的經驗,CLR 具備提供更高級別的調試APIICorDebug,這將在下面從「經常使用的調試方案」的圖像中顯示的BOTR

image.png

此外,還有很好的描述了不一樣部分如何在管理斷點如何工做中相互做用,雖然描述是上圖中的相反!

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。實際上,ICorDebugAPI僅在CLR v4中添加了對故障轉儲調試的支持。任何調試CLR v2崩潰轉儲的人根本沒法使用ICorDebug

(有關其餘文章,請參閱SOS和ICorDebug

ICorDebugAPI其實是分紅多個接口,也有在他們的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程序。

最後,若是你想看看ICorDebugAPI在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正在使用的不一樣堆大小的摘要:

image.png

(來自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接口,這裏列出了我遇到的一些內容:

記憶轉儲(Memory Dumps)

咱們要看的最後一個區域是「內存轉儲」,能夠從實時系統中捕獲並離線分析。.NET運行時一直很好地支持在Windows上建立「內存轉儲」,如今.NET Core是「跨平臺」,也能夠在其餘操做系統上使用相同的工具。

「內存轉儲」的一個問題是,獲取SOS和DAC文件的正確匹配版本可能會很是棘手。幸運的是,Microsoft剛剛發佈瞭如下dotnet symbolCLI工具

能夠下載任何給定核心轉儲,minidump或任何支持平臺的文件格式(如ELF,MachO,Windows DLL,PDB和便攜式PDB)的調試所需的全部文件(給出coreclr模塊的符號,模塊,SOS和DAC)。

最後,若是你花費任什麼時候間分析'內存轉儲',你真的應該看看微軟幾年前發佈的優秀的CLR MD庫。我以前已經寫過你能夠用它作什麼,但簡而言之,它容許你經過一個直觀的C#API與內存轉儲交互,其中的類能夠訪問ClrHeapGC RootsCLR ThreadsStack Frames更多。實際上,除了實現工做所需的時間以外,CLR MD還能夠實現大多數(若是不是所有)SOS命令

可是從宣佈帖子來看它是如何運做

ClrMD託管庫是CLR僅內部調試API的包裝器。雖然這些僅內部API對於診斷很是有用,但咱們不支持它們做爲公開的,有文檔的版本,由於它們很是難以使用而且與CLR的其餘實現細節緊密耦合。ClrMD經過圍繞這些低級調試API提供易於使用的託管包裝來解決此問題。

經過在官方支持的庫中提供這些API,Microsoft使開發人員可以在CLRMD之上構建各類工具,這是一個很好的結果!


總而言之,.NET Runtime提供了普遍的診斷,調試和分析功能,能夠深刻了解CLR內部的狀況。

相關文章
相關標籤/搜索