.Net Core服務診斷排查
前言:
近期在項目中出現了幾次服務內存資源佔用較高的情況,特回顧梳理下排查過程以及對相應問題的排查方法總結。
一、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是最完整的方式