.Net Core在Linux環境dump分析

前言

在本地開發調試的時候,基於VS的工具能方便看出內存泄露的信息:
在這裏插入圖片描述

但到了線上,一般都是在linux環境中,並且服務運行在docker上,這時出現內存泄露,CPU異常等情況,就無法直接調試,只能把docker中在允許的服務內存下來dump信息,進行分析,思路上就這幾步:

  1. 把運行時的內存給dump下來,傳到本地
  2. 能正確讀取出dump信息
  3. 分析原因

1. 生成dump文件

生成dump文件,依賴createdump工具,這個工具是.net core runtime自帶的,所以只要運行在.net core上的項目, 就可以直接使用該工具。

  1. 進行容器內部,dockername 可以通過docker ps得到
docker exec -it dockername /bin/bash
  1. 找到工具對應的目錄:
find /usr/share -name createdump

在這裏插入圖片描述

  1. 通過上面的路徑執行createdump,就會保存當前容器在運行時的信息。
    1代表容器內要保存的服務進程號, 如果只是1個服務,默認一般默認爲1,最終得到一個createdump.1的文件
/usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.0/createdump 1

如果出現以下信息:
Writing minidump with heap to file /tmp/coredump.1
ptrace(ATTACH, 1) FAILED Operation not permitted
說明沒有權限,需要在docker run的時候帶上命令 --privileged=true 獲取到root權限。

  1. 從容器中移出, 並放到自己希望的位置上。
docker cp dockername:/tmp/coredump.1 ./

2. 讀取dump文件的三個方式

現在已經有了coredump.1,要想辦法讀取coredump.1進行下一步的分析。
方案有多種,但是最終都是通過sos命令來查看dump信息。
有以下三條路線:

通過windbg+sos讀取

讀取dump時需所處環境:windows
這塊沒有嘗試,理論上似乎可以。雖然windbg是只能在windows上運行,但結合sos應該可以在windows中讀取dump。

dotnet自帶的dotnet-dump進行讀取

測試讀取dump時需所處環境:linux
這個工具的好處,相比下面lldb+sos的方案,安裝方便, 官方文檔說明點此

  1. 安裝dotnet-dump
dotnet tool install -g dotnet-dump

設置路徑, 結合實際dotnet所在目錄

export PATH=$PATH:xxx/.dotnet/tools
export DOTNET_ROOT="xxx/dotnet"
  1. 載入dump文件
dotnet-dump analyze coredump.1

進入後,執行clrthreads,就會列出當時正在運行的託管線程。

clrthreads

如果無法得到預期結果,出現了:
Failed to load data access module, 0x80004005
Can not load or initialize libmscordaccore.so. The target runtime may not be initialized.
說明必須依賴libmscordaccore.so,但是沒有被加載。可惜dotnet-dump工具還不支持單獨setclrpath功能,無法載入這個so文件。
通過github看3.1.57502之後的版本應該能支持單獨setclrpath了, 因爲代碼已經改了。

使用lldb+sos讀取(推薦)

測試讀取dump時需所處環境:Ubuntu
爲什麼是Ubuntu?因爲lldb版本在Ubuntu環境下安裝會比較簡單。

  1. 安裝lldb
    分析.net core2.1及以上的需要裝lldb-3.9,2.1之前的需要裝3.6版本了。
apt-get update && apt-get install -y \
    cmake llvm-3.9 \
    clang-3.9 \
    lldb-3.9 \
    liblldb-3.9-dev \
    libunwind8 \
    libunwind8-dev \
    gettext \
    libicu-dev \
    liblttng-ust-dev \
    libcurl4-openssl-dev \
    libssl-dev \
    uuid-dev \
    libnuma-dev \
    libkrb5-dev

安裝後通過lldb-3.9命令,能進入就代表正常。
在這裏插入圖片描述
2. 確認sos插件可以使用:
進入lldb後,輸入soshelp,能看到以下信息確認soshelp可以使用:
在這裏插入圖片描述
如果看不到:
版本是.net core3及之後的新版:退出lldb,安裝dotnet-sos後就能顯示

版本是.net core3之前的舊版本:在lldb里加載下sos插件,然後再調用下soshelp就能顯示了。

plugin load 你的路徑/dotnet/shared/Microsoft.NETCore.App/對應版本/libsosplugin.so
  1. 都安裝完了,帶上dump文件測試下
lldb-3.9 $(which dotnet) --core 你的dump文件路徑/coredump.1
進入到lldb後
如果是.net core3之前的版本,需要:
plugin load 你的路徑/dotnet/shared/Microsoft.NETCore.App/對應版本/libsosplugin.so

查看下當前dump文件裏的線程,輸入sos Threads後就能看到:
在這裏插入圖片描述
比如想看ID 11的線程詳情,可以先setsostid 14 11鎖定線程:在這裏插入圖片描述
然後再sos ClrStack查看線程內部信息
在這裏插入圖片描述

如果sos Threads後無法得到預期結果,出現了:
Failed to load data access module, 0x80004005
Can not load or initialize libmscordaccore.so. The target runtime may not be initialized.
說明必須依賴libmscordaccore.so,執行setclrpath:
setclrpath 你的路徑/dotnet/shared/Microsoft.NETCore.App/對應的.net core版本

3.分析

我們已經能通過sos的命令顯示出堆棧信息,通過這些信息就可以進行分析。
首先一定要熟悉sos裏面的每個命令,因爲上面不管哪種讀取dump方式,其實最終都是依靠sos插件。
然後根據遇到的不同情況再做不同角度的分析, 這裏順便連接一些通用的分析方法:
內存使用過多的情況分析
CPU過高的情況分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章