.Net Core服務診斷排查

語言: CN / TW / HK

前言:

近期在專案中出現了幾次服務記憶體資源佔用較高的情況,特回顧梳理下排查過程以及對相應問題的排查方法總結。

一、Dump抓取

抓取dump的方式有多種,下面介紹幾種常用的:

1. 工作管理員中找到程式程序,右鍵選單: 建立轉儲存檔案

注意:需要以程式執行的位數執行工作管理員抓取Dump

2. DotNet 全域性工具:dotnet-dump;工具可適用於Windows、Linux、macOS平臺

a) 安裝全域性dotnet-dump工具:

dotnet tool install --global dotnet-dump

b) 使用該工具抓取dump:

dotnet-dump collect [-h|--help] [-p|--process-id] [-n|--name] [--type] [-o|--output] [--diag]
    • -h|--help :顯示命令列幫助。
    • -p|--process-id <PID> :指定從中收集轉儲的程序的 ID 號。
    • -n|--name <name> :指定從中收集轉儲的程序的名稱。
    • --type <Full|Heap|Mini> :指定轉儲型別,它確定從程序收集的資訊的型別。 有三種類型:Full - 最大的轉儲,包含所有記憶體(包括模組映像)。Heap - 大型且相對全面的轉儲,其中包含模組列表、執行緒列表、所有堆疊、異常資訊、控制代碼資訊和除對映影象以外的所有記憶體。Mini - 小型轉儲,其中包含模組列表、執行緒列表、異常資訊和所有堆疊。如果未指定,則 Full 為預設型別。
    • -o|--output <output_dump_path> :應在其中寫入收集的轉儲的完整路徑和檔名。如果未指定:在 Windows 上預設為 .\dump_YYYYMMDD_HHMMSS.dmp ;在 Linux 上預設為 ./core_YYYYMMDD_HHMMSS ;YYYYMMDD 為年/月/日,HHMMSS 為小時/分鐘/秒。
    • --diag :啟用轉儲收集診斷日誌記錄。

3、ProcDump抓取Dump工具:自動抓取

命令語法:

procdump.exe [-mm] [-ma] [-mp] [-mc Mask] [-md Callback_DLL] [-mk]
             [-n Count]
             [-s Seconds]
             [-c|-cl CPU_Usage [-u]]
             [-m|-ml Commit_Usage]
             [-p|-pl Counter_Threshold]
             [-h]
             [-e [1 [-g] [-b]]]
             [-l]
             [-t]
             [-f  Include_Filter, ...]
             [-fx Exclude_Filter, ...]
             [-o]
             [-r [1..5] [-a]]
             [-at Timeout]
             [-wer]
             [-64]
             {
                 {{[-w] Process_Name | Service_Name | PID} [Dump_File | Dump_Folder]}
             |
                 {-x Dump_Folder Image_File [Argument, ...]}
             }

引數說明:

引數 說明
-a 避免中斷。 需要 -r。 如果觸發器會導致目標因超出併發轉儲限制而長時間掛起,將跳過觸發器。
-at 避免超時中斷。 在 N 秒時取消觸發器的集合。
-b 將除錯斷點視為異常 (否則忽略它們) 。
-c CPU 閾值,用於建立程序的轉儲。
-cl CPU 閾值,低於該閾值可建立程序的轉儲。
-d 呼叫指定 DLL 的名為 MiniDumpCallbackRoutine 的小型轉儲回撥例程。
-e 當程序遇到未經處理異常時編寫轉儲。 包括 1,以在出現第一機會異常時建立轉儲。
-f 篩選第一個可能異常。 支援萬用字元 (*) 。 若要僅顯示名稱而不進行轉儲,請使用空白 ("") 篩選器。
-fx 篩選 (排除) 異常內容和除錯日誌記錄。 支援萬用字元。
-g 在託管程序中作為本機偵錯程式執行, (互操作) 。
-h 如果程序有掛起的視窗, (在至少 5 秒未響應視窗訊息時寫入) 。
-i 將 ProcDump 安裝為 AeDebug 事後偵錯程式。 僅支援使用 -ma、-mp、-d 和 -r 作為附加選項。
-k 克隆到 (-r) 或轉儲收集結束時終止程序
-l 顯示程序的除錯日誌記錄。
-m 記憶體提交閾值(以 MB 為單位)用於建立轉儲。
-ma 編寫包含所有程序記憶體的轉儲檔案。 預設轉儲格式僅包含執行緒和處理資訊。
-mc 編寫自定義轉儲檔案。 包括由指定的十六進位制MINIDUMP_TYPE掩碼 (記憶體) 。
-md 編寫回調轉儲檔案。 包括由指定 DLL 的名為 MiniDumpCallbackRoutine 的 MiniDumpWriteDump 回撥例程定義的記憶體。
-mk 同時編寫核心轉儲檔案。 包括程序中執行緒的核心堆疊。 使用克隆 (-r) 時,OS 不支援核心轉儲 (-mk) 。 使用多個轉儲大小時,會針對每個轉儲大小執行核心轉儲。
-ml 當記憶體提交低於指定的 MB 值時觸發。
-mm 使用預設模式編寫 (轉儲) 。
-mp 使用執行緒和控制代碼資訊以及所有讀/寫程序記憶體編寫轉儲檔案。 為了最大程度地減小轉儲大小,將搜尋大於 512MB 的記憶體區域,如果找到,則排除最大的區域。 記憶體區域是大小相同的記憶體分配區域的集合。 刪除此記憶體 (快取) 將Exchange和SQL Server轉儲減少 90% 以上。
-n 退出前要寫入的轉儲數。
-o 覆蓋現有的轉儲檔案。
-p 超過閾值時,對指定效能計數器觸發。 注意:若要在程序有多個例項執行時指定程序計數器,請使用具有以下語法的程序 ID:"\Process (< name > _ < pid >) \counter"
-pl 當效能計數器低於指定值時觸發。
-r 使用克隆進行轉儲。 併發限制是可選的 (預設為 1,最大為 5) 。
警告:高併發值可能會影響系統性能。
- Windows 7:使用反射。 OS 不支援 -e。
- Windows 8.0:使用反射。 OS 不支援 -e。
- Windows 8.1+:使用 PSS。 支援所有觸發器型別。
-s 寫入轉儲之前連續秒 (預設值為 10) 。
-t 在程序終止時寫入轉儲。
-u 將 CPU 使用率視為與 -c (一) 。
作為唯一選項,解除安裝 ProcDump 作為事後偵錯程式。
-w 等待指定的程序啟動(如果該程序未執行)。
-wer 將 (最大) 排隊到Windows 錯誤報告。
-x 使用可選引數啟動指定的映像。 如果是應用商店應用程式或包,ProcDump 將在下次啟用時啟動, (啟用) 。
-64 預設情況下,在 64 位程序上執行時,ProcDump 將捕獲 32 位程序的 32 位Windows。 此選項將替代 以建立 64 位轉儲。 僅用於 WOW64 子系統除錯。
-? 使用 -? -e 檢視示例命令列。

示例:

當程序在 5 秒鐘內 CPU 使用率超過 50% 時,最多寫入 2 個名為"w3wp"的程序的微型轉儲:

procdump -ma -s 5 -n 2 -c 50 w3wp

二、Dump分析

根據前面幾方式得到的Dump檔案,下一步就是對Dump進行分析確認問題原因:

1、Windbug Preview 分析:

Windbg Preview  是windows平臺上的一款相當強大的除錯工具,可以從msdn網站下載得到,最新版本包含在windows sdk中,預設會被安裝在C:\Program Files\Debugging Tools for Windows 目錄中,可以直接把這個目錄打包複製到其它機器上使用。

Windbug常用命令:

    • !analyze -v     自動分析dump
    • kv     檢視棧回溯
    • .ecxr     顯示當前異常上下文
    • .cxr     切換異常幀上下文
    • .exr     顯示異常資訊
    • .frame     設定當前棧幀
    • dv     顯示當前棧幀區域性變數
    • dd     顯示記憶體中的資料
    • r     檢視暫存器
    • lmvm     檢視模組詳細資訊
    • r     可以顯示系統崩潰時的暫存器,和最後的命令狀態
    • dd     顯示當前記憶體地址,dd 引數:顯示引數處的記憶體
    • u     可以顯示反彙編的指令
    • kb     顯示call stack 內容

2、VS分析Dump:

a) 使用VS開啟dump檔案:

可以看到該dump的基本資訊,接下來設定符號檔案:

b) 分析Dump中記憶體情況: 除錯託管記憶體

可以看到當前託管資源中記憶體佔用情況,如果有多個dump還可以對比dump中記憶體增長變化

檢視物件內容:

c) 檢視當前執行的程序列表:(設定了符號檔案後可以檢視當前堆疊資訊,以及跳轉到程式碼邏輯)

3、dotnet-dump分析:

分析命令:

dotnet-dump analyze <dump_path> [-h|--help] [-c|--command]

SOS命令支援:

命令 函式
soshelp|help 顯示所有可用命令
soshelp|help <command> 執行指定的命令。
exit|quit 退出互動模式。
clrstack <arguments> 僅提供託管程式碼的堆疊跟蹤。
clrthreads <arguments> 列出正在執行的託管執行緒。
dumpasync <arguments> 顯示有關垃圾回收堆上非同步狀態機的資訊。
dumpassembly <arguments> 顯示有關指定地址處程式集的詳細資訊。
dumpclass <arguments> 顯示有關指定地址處的 EEClass 結構的資訊。
dumpdelegate <arguments> 顯示有關指定地址處的委託的資訊。
dumpdomain <arguments> 顯示所有 AppDomain 和指定域中的所有程式集的資訊。
dumpheap <arguments> 顯示有關垃圾回收堆的資訊和有關物件的收集統計資訊。
dumpil <arguments> 顯示與託管方法關聯的 Microsoft 中間語言 (MSIL)。
dumplog <arguments> 將記憶體中壓力日誌的內容寫入到指定檔案。
dumpmd <arguments> 顯示有關指定地址處的 MethodDesc 結構的資訊。
dumpmodule <arguments> 顯示有關指定地址處的模組的資訊。
dumpmt <arguments> 顯示有關指定地址處的 MethodTable 的資訊。
dumpobj <arguments> 顯示有關位於指定地址處的物件的資訊。
dso|dumpstackobjects <arguments> 顯示在當前堆疊的邊界內找到的所有託管物件。
eeheap <arguments> 顯示有關內部執行時資料結構所使用的程序記憶體的資訊。
finalizequeue <arguments> 顯示所有已進行終結註冊的物件。
gcroot <arguments> 顯示有關對指定地址處的物件的引用(或根)的資訊。
gcwhere <arguments> 顯示傳入引數在 GC 堆中的位置。
ip2md <arguments> 顯示 JIT 程式碼中指定地址處的 MethodDesc 結構。
histclear <arguments> 釋放由 hist* 命令系列使用的任何資源。
histinit <arguments> 從儲存在除錯物件中的壓力日誌初始化 SOS 結構。
histobj <arguments> 顯示與 <arguments> 相關的垃圾回收壓力日誌重定位。
histobjfind <arguments> 顯示在指定地址處引用物件的所有日誌項。
histroot <arguments> 顯示與指定根的提升和重定位相關的資訊。
lm|modules 顯示程序中的本機模組。
name2ee <arguments> 顯示 <argument> 的  MethodTable 和  EEClass 結構。
pe|printexception <arguments> 顯示從 Exception 類派生的  <argument> 的任何物件。
setsymbolserver <arguments> 啟用符號伺服器支援
syncblk <arguments> 顯示 SyncBlock 持有者資訊。
threads|setthread <threadid> 設定或顯示 SOS 命令的當前執行緒 ID。

例如:

dotnet-dump analyze "w3wp (2).DMP"

三、案例:

問題現象:xxx服務請求響應耗時較長,導致業務無法正常開展

排查過程:

1、檢視記憶體情況,Oracle連線數量較大

2、檢視執行緒中都為Oracle連線等待:

3、最終確認請求被卡到了Oracle處理

四、總結

1、在排查服務相關問題時,分析dump方式是最直接的方式;而vs方式分析dump是最直接、方便、簡單的方式。

2、通過windbug分析dump是最完整的方式

參考:

windbg命令