原文鏈接:https://www.cnblogs.com/yaohong/p/16046670.html,轉載需經同意。
1.問題由來
近期發現堡壘機環境有如下問題,systemd占用大量cpu:
2.問題定位
2.1.什么是systemd
咋們可以先從systemd這個進程入手分析這個問題:
根據文檔《systemd (簡體中文)》文檔,我們可知如下圖信息:
作用:
systemd 會給每個用戶生成一個 systemd 實例,用戶可以在這個實例下管理服務,啟動、停止、啟用以及禁用他們自己的單元。
工作原理:
“從 systemd 226 版本開始,/etc/pam.d/system-login 默認配置中的 pam_systemd 模塊會在用戶首次登錄的時候, 自動運行一個 systemd --user 實例。 只要用戶還有會話存在,這個進程就不會退出;用戶所有會話退出時,進程將會被銷毀。”。
根據上面這段話,我們可以猜測:ssh登錄時可以創建systemd進程,ssh退出登錄時可以銷毀systemd --user進程。
懷着這個猜測,我們進行下面的研究分析。
2.2.systemd進程怎么產生的
首先,我們在第一個終端,執行下面的命令創建test3用戶:
$ groupadd test3 $ useradd -g test3 -m -d /home/test3 -s /bin/bash test3 $ passwd test3
然后,在第二個終端,執行ssh登錄test3
$ ssh test3@172.21.0.46
接着,在第一個終端,執行如下命令過濾新產生的test3 用戶的systemd進程
$ top -bc |grep systemd
得到如下圖回顯,可知:1.9秒前產生了一個pid為19178的systemd --user進程,此進程占用了40.9%的CPU。
於是對接systemd進程創建得出如下結論:
systemd版本大於226(centos7為219、ubuntu1604為229),ssh 登錄會產生登錄用戶對應的systemd進程。
2.3.systemd進程為何沒有被銷毀
既然ssh登錄會產生systemd進程,那退出ssh登錄應該會銷毀對應systemd進程。
於是,我們在2.2中的第二個窗口執行 exit
退出ssh連接。
$ exit
然后,再執行如下命令,發現沒有test3用戶的systemd進程了。
$ top -bc | grep systemd
至此,我們對systemd進程的退出也有了了解:退出ssh連接即可銷毀對應systemd進程
。
但,為什么我們看到的騰訊雲環境上systemd進程一直沒有被銷毀?
此時我想到了 非正常退出ssh連接
,
如2.1章節,在第二個終端,執行ssh登錄test3,再如下圖直接點“X”
直接關閉窗口,
然后,在第一個終端,執行如下命令過濾新產生的test3 用戶的systemd進程
$ top -bc |grep systemd
test3用戶的systemd進程還存在,驚訝!!!
於是分別做如下操作對systemd進程關閉做測試,並得出相應結論:
- 1.xshell連內部vmware上虛擬機環境,點“X”號關閉窗口,對應systemd進程正常銷毀;
- 2.web端連公司堡壘機上的雲主機環境,點“X”號關閉窗口,對應systemd進程不能被銷毀;
- 3.web端通過部門內部運維平台連接內部虛擬機環境,點“X”號關閉窗口,對應systemd進程不能被銷毀;
於是對於systemd進程銷毀得出如下結論:
web端連接的虛擬機終端,直接點“X”號關閉窗口,登錄用戶對應的systemd進程都不能被銷毀,exit命令退出終端登錄可以銷毀,Xshell無此問題。
2.4.systemd進程吃CPU的原因
關於進程跟蹤我們很容易想到strace命令。
我們對2.1章節中創建的test3的systemd進程進行跟蹤。
得到如下回顯:
看這個進程是在不停的掃描磁盤。
關於這個問題,我在《google-cloud-kuberbetes-run-away-systemd-100-cpu-usage》一文中得到答案:
Docker在17.03和18.09版本之間的變化導致了大量的systemd活動,無論在pod中執行了什么。同時,只要runc發生change,它導致所有mount units被重新加載,作為執行存活探針的一部分。
於是針對這個猜想,我看了下k8s同一集群中systemd正常與異常的節點:
1.正常節點:
# cat /proc/mounts |wc 120 720 46377
2.異常節點:
# cat /proc/mounts |wc 1017 6102 341121
於是瞬間也有了結論:
systemd 進程cpu使用率太高是因為mount掛載點太多,mount有更新后,通過dbus通知到systemd重新遍歷所有mount, 遍歷操作比較耗cpu。
同時,既然說到和docker版本有關系,我便針對性找了兩個有差異的環境做docker版本對不:
- 1.ubuntu1604+mount掛載多+systemd正常環境
- 2.ubuntu1604+mount掛載多+systemd異常環境
由上圖我們發行,環境1中mount掛載為1537個,比環境2中mount掛載為1028個更高但是沒出現systemd吃cpu問題,可知系統相同情況下和docker版本有關。
對於什么情況下出現systemd占用高,我們得出如下結論:
systemd版本大於226(ubuntu1604為229)+docker版本為19.03.14,無論runc做了什么操作,dbus會通知systemd重新遍歷 mount,遍歷mout過多(cat /proc/mounts |wc命令查看)會導致systemd進程吃CPU。
三、解決方案
1.不使用web終端連接systemd版本大於226,docker>=19.03.14的環境,可以使用比如xshell連接。
2.針對runc活動導致systemd進程吃CPU問題,google GKE 團隊給出如下優化方案:
原文鏈接:https://www.cnblogs.com/yaohong/p/16046670.html
四、總結
1.systemd進程如何被創建:systemd版本大於226(centos7為219、ubuntu1604為229),ssh 登錄會產生登錄用戶對應的systemd --user進程。
2.systemd進程為何未被銷毀:web端連接的虛擬機終端,直接點“X”號關閉窗口,登錄用戶對應的systemd進程都不能被銷毀,exit命令退出終端登錄可以銷毀,Xshell無此問題。
3.systemd進程為何吃cpu:systemd版本大於226(ubuntu1604為229)+docker版本為19.03.14,無論runc做了什么操作,dbus會通知systemd重新遍歷 mount,如果遍歷mount過多(cat /proc/mounts |wc命令查看,700個會吃30%CPU,1000個會吃50%左右CPU)就會導致systemd進程吃CPU。
原文鏈接:https://www.cnblogs.com/yaohong/p/16046670.html
五、參考文檔
《systemd (簡體中文)》
《google-cloud-kuberbetes-run-away-systemd-100-cpu-usage》
《 原文鏈接:https://www.cnblogs.com/yaohong/p/16046670.html》