CentOS下top命令引起系統負載升高
系統內容:CentOS 6.5x86_64
一、問題表現
系統負載升高,某一個核的cpu資源被top進程耗盡,如所示:
二、分析過程
通過strace命令列印top進程資訊,出現大量重複的系統調用,如下:
查看top進程的fd資訊如下:
通過以上資訊推斷,top進程的輸入輸出異常,觸發select返迴文件描述符,但是檔案描述符未處理或處理不當造成select無限觸發,陷入死迴圈,佔用一個核的cpu資源。
下載procps-3.2.8查看top源碼,在第3398行找到了相關調用。如代碼所示標準輸入被放到了select調用裡,因為標準輸入錯誤導致觸發select返回fd,無tv時間長度的等待。
longfile_flags;intrc;charc;fd_setfs;FD_ZERO(&fs);FD_SET(STDIN_FILENO,&fs);file_flags=fcntl(STDIN_FILENO,F_GETFL);if(file_flags==-1)file_flags=0;fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK|file_flags);//check1st,incasetvzeroed(bysighandler)beforeitgotsetrc=chin(0,&c,1);if(rc<=0){//EOFisprettymucha"can'thappen"exceptforakernelbug.//WeshouldquicklydieviaSIGHUP,andthusnotspinhere.//if(rc==0)end_pgm(0);/*EOFfromterminal*/fcntl(STDIN_FILENO,F_SETFL,file_flags);select(1,&fs,NULL,NULL,&tv);fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK|file_flags);}if(chin(0,&c,1)>0){fcntl(STDIN_FILENO,F_SETFL,file_flags);do_key((unsigned)c);}else{fcntl(STDIN_FILENO,F_SETFL,file_flags);}
標準輸入的處理代碼如下:
staticintchin(intech,char*buf,unsignedcnt){intrc;fflush(stdout);if(!ech)rc=read(STDIN_FILENO,buf,cnt);else{tcsetattr(STDIN_FILENO,TCSAFLUSH,&Savedtty);rc=read(STDIN_FILENO,buf,cnt);tcsetattr(STDIN_FILENO,TCSAFLUSH,&Rawtty);}//maybethebeginningofalengthyescapesequencetcflush(STDIN_FILENO,TCIFLUSH);returnrc;//note:wedoNOTproduceavaid'string'}
rc為read傳回值,分三類返回正的位元組數、0(表示到達檔案末尾)、返回負值-1(表示出錯)。源碼中 rc==0的情況被注掉了(如)造成標準輸入fd未處理,select的逾時未生效。
top在運行時出現標準輸入異常這種情況一般是很難發生的,通過ps -fe 列印出了top的進程關係如下:
sudo 進程的pid變成1了,通過 ssh -t ‘strace -o sudo.strace sudo -i’ 抓取資訊如下:
在終端異常關閉(斷網)後,並未退出,將父進程設成1繼續運行。
經測試在ssh -t ‘sudo -i’ 這種方式登陸,sudo的父進程是sshd,當終端異常關閉時sudo會將自己的父進程改為1繼續運行。正常登陸後在運行sudo的,sudo的父進程一般為bash(也可能是其他shell),不會出現類似情況。
三、總結
因線上環境很多操作需要切換到root,為了方便在ssh登陸的時候加上了 -t ‘sudo -i’ 的參數,從而導致了悲劇的發生。捷徑隨好但要小心陷阱,一不小心就可能釀成大錯。
註:
setsid top 或者其他守護進程調用top,當終端異常退出引起標準輸入錯誤時都會造成top異常。
ubuntu系統不存在此問題,debian修複了此問題。
nicai@bugaosuni:~/procps-3.2.8/debian/patches$cattop_stdin_eof.patch
Description:Check
for
stdineof
if
term
Author:SamuelThibault<samuel.thibault@ens-lyon.org>
Bug-Debian:http:
//bugs.debian.org/458986
Reviewed-by:CraigSmall<csmall@debian.org>
Index:b/top.c
===================================================================
---a/top.c 2009-11-2421:00:34.000000000+1100
+++b/top.c 2009-11-2421:00:35.000000000+1100
@@-3408,9+3408,8@@
//check1st,incasetvzeroed(bysighandler)beforeitgotset
rc=chin(0,&c,1);
if
(rc<=0){
-
//EOFisprettymucha"can'thappen"exceptforakernelbug.
-
//WeshouldquicklydieviaSIGHUP,andthusnotspinhere.
-
//if(rc==0)end_pgm(0);/*EOFfromterminal*/
+
if
(rc==0)end_pgm(0);
/*EOFfromterminal,mayhappeniftop
+*erroneouslygetsdetachedfromit.*/
fcntl(STDIN_FILENO,F_SETFL,file_flags);
select(1,&fs,NULL,NULL,&tv);
fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK|file_flags);
nicai@bugaosuni:~/procps-3.2.8/debian/patches$
本文出自 “left_left” 部落格,請務必保留此出處http://linux521.blog.51cto.com/4099846/1579890