dotnet core除錯docker下生成的dump檔案
最近公司預生產環境的docker容器經常出現記憶體暴漲現象,有時會突然吃掉幾個G,觸發監控預警,造成容器重啟。
分析了各種可能原因,修復了可能發生的記憶體洩露,經測試本地正常,但是發到預生產還是會有記憶體暴漲現象,反而更改GC模式後記憶體使用保持較低水平,百思不得其解,所以想到使用除錯dump檔案方式來分析應用記憶體狀況。
環境:
lldb:3.9
dotnetcore:2.1.6
docker image:microsoft/dotnet:2.1.6-aspnetcore-runtime
(根據文件,dotnetcore2.0需要使用lldb3.6,但是我嘗試了沒有成功,lldb使用的dotnetcore版本與dump應用的dotnetcore版本要一致,由於core2.1現在官方只提供2.1.6的runtime檔案,故本次測試使用2.1.6版本,如果哪位童鞋在core2.0上除錯成功了,麻煩告訴我方法)
linux下需要使用lldb來進行dump分析,但是安裝這個太慢,所以我找了個安裝好的docker image使用,有興趣的也可以自行安裝,這裡就不介紹安裝過程了,.net core 本身提供了lldb sos 外掛,只要載入使用就好。
啟動一個.net core應用容器,這裡需要多加幾個引數,不然無法建立dump(另外多說一句,docker內crash coredump檔案無法生成也是許可權原因,我這邊啟動時都給了許可權,如果僅僅是需要使用.netcore提供createdump工具,只需要加--privileged=true):
docker run -d -p 80:80 --name dumptest --ulimit core=-1 --security-opt seccomp=unconfined --privileged=true dumptest:v1
--ulimit core=-1 不限制coredump大小
--security-opt seccomp=unconfined 允許容器執行全部系統呼叫
--privileged=true 允許createdump訪問其他程序
進入容器:
docker exec -it dumptest /bin/bash
建立dump檔案:
/usr/share/dotnet/shared/Microsoft.NETCore.App/2.1.6/createdump 1
(經觀察,容器內的跑的應用程序ID都是1,所以直接使用,也可以使用top命令來檢視程序ID,建立dump檔案在/tmp/coredump.1)
退出容器:
exit
在宿主機建立資料夾/data/docker,並將容器中的dump檔案拷貝到宿主機:
cd /&&mkdir data&&cd data&&mkdir docker
docker cp dumptest :/tmp/coredump.1 /data/docker
拉取lldb映象(此映象是lldb3.9的dotnetcore版本為2.1.5,有其他需求請自行查詢):
docker pull yyoda/dotnet-lldb
啟動lldb容器,並將coredump檔案路徑對映到容器內(如果想要長期使用不要帶--rm引數):
docker run -d -v /data/docker:/dump --rm -it --name lldb yyoda/dotnet-lldb:latest /bin/bash
映象內需要安裝dotnetcore2.1.6,為了方便安裝,在容器內部使用阿里源:
cd /data/docker
touch sources.list
將下面的源加入sources.list:
deb http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
進入lldb容器:
docker exec -it lldb /bin/bash
更新源:
mv /dump/sources.list /etc/apt/source.list
apt-get update
安裝dotnetcore2.1.6 runtime(由於網路等原因,如果失敗多試幾次):
wget -q https://packages.microsoft.com/config/ubuntu/14.04/packages-microsoft-prod.deb
dpkg -i packages-microsoft-prod.deb
apt-get install apt-transport-https
apt-get update
apt-get install dotnet-runtime-2.1
啟動lldb:
lldb-3.9 dotnet -c /dump/coredump.1 -o "plugin load /usr/share/dotnet/shared/Microsoft.NETCore.App/2.1.6/libsosplugin.so"
(如果sos載入失敗,啟動後輸入命令:plugin load /usr/share/dotnet/shared/Microsoft.NETCore.App/2.1.6/libsosplugin.so
如果runtime載入失敗,啟動後輸入命令:setclrpath /usr/share/dotnet/shared/Microsoft.NETCore.App/2.1.6)
輸入soshelp命令,出現下圖:
檢視堆上的物件型別分配情況(由於結果太多,這裡加入大於1024byte過濾):
dumpheap -stat -min 1024
檢視指定型別物件情況:
dumpheap -mt 00007f2a28b874e8 -min 1024
檢視指定物件情況:
dumpobj 00007f2a1400fc88
剩下的就是熟悉sos命令,不在贅述了,大家自行研究吧。。。