當前快訊:【JVM故障問題排查心得】「內存診斷系列」Docker容器經常被kill掉,k8s中該節點的pod也被驅趕,怎么分析?

2022-12-15 14:12:01 來源:51CTO博客

背景介紹

最近的docker容器經常被kill掉,k8s中該節點的pod也被驅趕。


【資料圖】

我有一個在主機中運行的Docker容器(也有在同一主機中運行的其他容器)。該Docker容器中的應用程序將會計算數據和流式處理,這可能會消耗大量內存。

該容器會不時退出。我懷疑這是由于內存不足,但不是很確定。我需要找到根本原因的方法。那么有什么方法可以知道這個集裝箱的死亡發生了什么?

容器層級判斷檢測

提到docker logs $container_id查看該應用程序的輸出。這永遠是我要檢查的第一件事。接下來,您可以運行docker inspect $container_id以查看狀態的詳細信息,例如:

"State": {        "Status": "exited",        "Running": false,        "Paused": false,        "Restarting": false,        "OOMKilled": false,        "Dead": false,        "Pid": 0,        "ExitCode": 2,        "Error": "",        "StartedAt": "2016-06-28T21:26:53.477229071Z",        "FinishedAt": "2016-06-28T21:26:53.478066987Z"    }

重要的一行是“ OOMKilled”,如果您超出了容器的內存限制,并且Docker殺死了您的應用程序,則該行將為true。您可能還需要查找退出代碼,以查看其是否標識出您的應用退出的原因。

Docker內部,這僅表示docker本身是否會殺死您的進程,并要求您在容器上設置內存限制。Docker外部,如果主機本身內存不足,Linux內核可以銷毀進程。發生這種情況時,Linux通常會在/ var / log中寫入日志。使用Windows和Mac上的Docker Desktop,您可以在docker設置中調整分配給嵌入式Linux VM的內存。可以通過閱讀日志來了解容器內的進程是否被OOM殺死。OOMkill是由內核啟動的,因此每次發生時,都會在中包含很多行/var/log/kern.log,例如:
python invoked oom-killer: gfp_mask=0x14000c0(GFP_KERNEL), nodemask=(null), order=0, oom_score_adj=995oom_kill_process+0x22e/0x450Memory cgroup out of memory: Kill process 31204 (python) score 1994 or sacrifice childKilled process 31204 (python) total-vm:7350860kB, anon-rss:4182920kB, file-rss:2356kB, shmem-rss:0kB

Linux操作系統的進程服務發生被killed的原因是什么

在Linux中,經常會遇到一些重要的進程無緣無故就被killed,而大多數的經驗之談就是系統資源不足或內存不足所導致的。

當Linux系統資源不足時,Linux內核可以決定終止一個或多個進程,內存不足時會在系統的物理內存耗盡時觸發OOM killed,可以利用“dmesg | tail -N”命令來查看killed的近N行日志。

常規的宕機監控之類

在服務宕機或者重啟之前我們的常規操作就是采用ps指令判定服務的增長趨勢以及展示真實使用的資源的大小的前幾位排名。

Linux下顯示系統進程的命令ps,最常用的有ps -ef 和ps aux。這兩個到底有什么區別呢?

??ps -ef??指令代表著"SystemV風格",而??ps aux??代表著’BSD風格‘。

由上圖所示,可以分析出對應的數據結構模型。

USER      //用戶名%CPU      //進程占用的CPU百分比%MEM      //占用內存的百分比VSZ       //該進程使用的虛擬內存量(KB)RSS       //該進程占用的固定內存量(KB)resident set sizeSTAT      //進程的狀態START     //該進程被觸發啟動時間TIME      //該進程實際使用CPU運行的時間

其中CPU算是第3個位置、內存MEM算是第4個位置,虛擬內存VSZ是第5個位置,記住這個后面我們會使用這個方式進行排序。

查看當前系統內CPU占用最多的前10個進程(欄位屬于第3個)

ps auxw | sort -rn -k3 | head -10
ps auxw指令(BSD風格)
u:以用戶為主的格式來顯示程序狀況x:顯示所有程序,不以終端機來區分w:采用寬闊的格式來顯示程序狀況
sort排序指令
sort -rn -k5

-n是按照數字大小排序(-n 這代表著排除n行的操作處理),-r是以相反順序,-k是指定需要排序的欄位

ps auxw | head -1

內存消耗最多的前10個進程(欄位屬于第4個)

ps auxw | head -1;ps auxw|sort -rn -k4|head -10

虛擬內存使用最多的前10個進程(欄位屬于第5個)

ps auxw|head -1;ps auxw|sort -rn -k5|head -10
去掉x參數的結果
ps auw | head -1; ps auw|sort -rn -k4 | head -10
stat取值含義
D      //無法中斷的休眠狀態(通常 IO 的進程);R      //正在運行可中在隊列中可過行的;S      //處于休眠狀態;T      //停止或被追蹤;W      //進入內存交換 (從內核2.6開始無效);X      //死掉的進程 (基本很少見);Z      //僵尸進程;<      //優先級高的進程N      //優先級較低的進程L      //有些頁被鎖進內存;s      //進程的領導者(在它之下有子進程);l      //多線程,克隆線程(使用 CLONE_THREAD, 類似 NPTL pthreads);+      //位于后臺的進程組;

dmesg的命令分析

有幾個工具/腳本/命令 可以更輕松地從該虛擬設備讀取數據,其中最常見的是 dmesg 和 journalctl。

輸入dmesg指令進行egrep正則表達式匹配killed的進程信息,將輸出對應的進程信息。

dmesg | egrep -i -B100 "killed process"

dmesg | grep -i -B100 "killed process"

以上的指令就可以輸出最近killed的信息,其中-B100,表示 "killed process’之前的100行內容,與head的指令非常的相似。

如果我們看到了oom-kill的字樣之后,就可以判斷它是被內存不足所導致的kill,oom-kill之后,就是描述那個被killed的程序的pid和uid。

Out of memory: Killed process 1138439 (python3) total-vm:8117956kB, anon-rss:5649844kB,內存不夠
total_vm和rss的指標值
total_vm:總共使用的虛擬內存 Virtual memory use (in 4 kB pages),8117956/1024(得到MB)/1024(得到GB)=7.741GBrss:常駐內存使用Resident memory use (in 4 kB pages) 5649844/1024/1024=5.388GB
案例1:查看到pod被驅趕的原因
[3899860.525793] Out of memory: Kill process 64058 (nvidia-device-p) score 999 or sacrifice child[3899860.526961] Killed process 64058 (nvidia-device-p) total-vm:126548kB, anon-rss:2080kB, file-rss:0kB, shmem-rss:0kB
案例2:查看到docker容器被kill 的原因
[3899859.737598] Out of memory: Kill process 27562 (jupyter-noteboo) score 1000 or sacrifice child[3899859.738640] Killed process 27562 (jupyter-noteboo) total-vm:215864kB, anon-rss:45928kB, file-rss:0kB, shmem-rss:0kB

journalctl命令 – 查看指定的日志信息

當內存不足時,內核會將相關信息記錄到內核日志緩沖區中,該緩沖區可通過 /dev/kmsg 獲得。除了上面的dmesg之外,還有一個journalctl。

語法格式: journalctl [參數]

常用參數:
查看Killed日志

使用sudo dmesg | tail -7命令(任意目錄下,不需要進入log目錄,這應該是最簡單的一種)而journalctl命令來自于英文詞組“journal control”的縮寫,其功能是用于查看指定的日志信息。

journalctl指令介紹

在RHEL7/CentOS7及以后版本的Linux系統中,Systemd服務統一管理了所有服務的啟動日志,帶來的好處就是可以只用journalctl一個命令,查看到全部的日志信息了。

查看所有日志(默認情況下 ,只保存本次啟動的日志)
journalctl
查看內核日志(不顯示應用日志)
journalctl -k
查看系統本次啟動的日志
journalctl -bjournalctl -b -0
查看上一次啟動的日志(需更改設置)
journalctl -b -1
查看指定時間的日志
journalctl --since=“2021-09-16 14:22:02”journalctl --since “30 min ago”journalctl --since yesterdayjournalctl --since “2021-01-01” --until “2021-09-16 13:40”journalctl --since 07:30 --until “2 hour ago”
顯示尾部的最新10行日志
journalctl -n
顯示尾部指定行數的日志
journalctl -n 15
實時滾動顯示最新日志
journalctl -f
查看指定服務的日志
journalctl /usr/lib/systemd/systemd
比如查看docker服務的日志
systemctl status docker
查看某個 Unit 的日志
journalctl -u nginx.servicejournalctl -u nginx.service --since today
實時滾動顯示某個 Unit 的最新日志
journalctl -u nginx.service -f
合并顯示多個 Unit 的日志
$ journalctl -u nginx.service -u php-fpm.service --since today

標簽: 虛擬內存 應用程序 休眠狀態

上一篇:C語言-操作符詳解
下一篇:HTML文本標簽和span標簽和背景圖片