長期生活在 Linux 環境裡,漸漸地就有一種環保意識油然而生。比如,我們會在登入提示裡寫上“悟空,我跟你說過叫你不要亂扔東西,亂扔東西是不對的。哎呀我話沒說完你怎麼把棍子扔掉了?月光寶盒是寶物,亂扔它會汙染環境,要是砸到小朋友怎麼辦?就算砸不到小朋友,砸到了花花草草也不好嘛...”;在使用者預設目錄裡放一個題為 “自覺保護環境 請勿堆放垃圾”的空檔案,並用 chattr +i 設為不可修改;看到垃圾檔案就立即掃入 /tmp 目錄,然後發廣播通知垃圾製造者自己去 /tmp 認領,且警告其下不為例...我們深知,系統內容的整潔有利於系統管理員保持良好的心情、清晰的思路和穩定的工作狀態。
有一類垃圾卻並非這麼容易打掃,那就是我們常見的狀態為 D (Uninterruptible sleep) ,以及狀態為 Z (Zombie) 的垃圾進程。這些垃圾進程要麼是求而不得,像怨婦一般等待資源(D),要麼是僵而不死,像冤魂一樣等待超度(Z),它們在 CPU run_queue 裡滯留不去,把 Load Average 弄的老高老高,沒看過我前一篇blog的國際友人還以為這兒民怨沸騰又出了什麼大事呢。怎麼辦?開槍!kill -9!看你們走是不走。但這兩種垃圾進程偏偏是刀槍不入的,不管換哪種槍法都殺不掉它們。無奈,只好reboot,像剿滅禽流感那樣不分青紅皂白地一律撲殺!
悟空,我們所營運的可是24*7全天候對外部客戶服務的系統,怎麼能動不動就 reboot ?我們的考核指標可是4個9(99.99%,全年計劃外當機時間不得超過52分鐘34秒),又不是4個8,你稍微遇到點事就reboot,還要不要可用性了?再說,現在社會都開始奔和諧去了,我們對於 D 和 Z 這兩種垃圾進程,也該儘可能採取慈悲手段,能解決其困難的,就創造條件,解決其實際困難,能消除其冤結的,就誦經燒紙,消除其前世冤結,具體問題應具體分析具體解決,濫殺無辜只會導致冤冤相報因果迴圈...$^#$%#%^@#
貧僧還是回來說正題。怨婦 D,往往是由於 I/O 資源得不到滿足,而引發等待,在核心源碼 fs/proc/array.c 裡,其文字定義為“ "D (disk sleep)", /* 2 */ ”(由此可知 D 原是Disk的打頭字母),對應著 include/linux/sched.h 裡的“ #define TASK_UNINTERRUPTIBLE 2 ”。舉個例子,當 NFS 服務端關閉之時,若未事先 umount 相關目錄,在 NFS 用戶端執行 df 就會掛住整個登入工作階段,按 Ctrl+C 、Ctrl+Z 都無濟於事。中斷連線再登入,執行 ps axf 則看到剛才的 df 進程狀態位已變成了 D ,kill -9 無法殺滅。正確的處理方式,是馬上恢複 NFS 服務端,再度提供服務,剛才掛起的 df 進程發現了其苦苦等待的資源,便完成任務,自動消亡。若 NFS 服務端無法恢複服務,在 reboot 之前也應將 /etc/mtab 裡的相關 NFS mount 項刪除,以免 reboot 過程例行調用 netfs stop 時再次發生等待資源,導致系統重啟過程掛起。
冤魂 Z 之所以殺不死,是因為它已經死了,否則怎麼叫 Zombie(殭屍)呢?冤魂不散,自然是生前有結未解之故。在UNIX/Linux中,每個進程都有一個父進程,進程號叫PID(Process ID),相應地,父進程號就叫PPID(Parent PID)。當進程死亡時,它會自動關閉已開啟的檔案,捨棄已佔用的記憶體、交換空間等等系統資源,然後向其父進程返回一個退出狀態值,報告死訊。如果程式有 bug,就會在這最後一步出問題。兒子說我死了,老子卻沒聽見,沒有及時收棺入殮,兒子便成了殭屍。在UNIX/Linux中消滅殭屍的手段比較殘忍,執行 ps axjf 找出殭屍進程的父進程號(PPID,第一列),先殺其父,然後再由進程天子 init(其PID為1,PPID為0)來一起收拾父子殭屍,超度亡魂,往生極樂。注意,子進程變成殭屍只是礙眼而已,並不礙事,如果殭屍的父進程當前有要務在身,則千萬不可貿然殺之。
關於ZOMBIE進程:
這些進程已經死亡,但沒有釋放系統資源,包括記憶體和一些一些系統資料表等,如果這樣的進程很多,會引發系統問題。用ps -el看出的進程狀態如果是Z,就是殭屍進程。
ps -ef|grep defunc可以找出殭屍進程.
有些ZOMBIE進程時用kill -9也不能殺死,而且消耗了很多系統資源不能釋放,如果系統在shutdown時發出資訊:some process wouldn’t die. 這就意味這有些進程不能被reboot發出的kill –9殺掉,這些很可能就是殭屍進程。
可以用ps 的 – l 選項,得到更詳細的進程資訊.
F(Flag):一系列數位和,表示進程的目前狀態。這些數位含義為:
00:若單獨顯示,表示此進程已被終止。
01:進程是核心進程的一部分,常駐於系統主存。如: sched、 vhand 、bdflush 等。
02:Parent is tracing process.
04 :Tracing parent's signal has stopped the process; the parent is waiting ( ptrace(S)).
10:進程在優先順序低於或等於25時,進入休眠狀態,而且不能用訊號喚醒,例如在等待一個inode被建立時
20:進程被裝入主存(primary memory)
40:進程被鎖在主存,在事務完成前不能被置換 e
S(state of the process )
O:進程正在處理器運行
S:休眠狀態(sleeping)
R:等待運行(runable)
I:空閑狀態(idle)
Z:殭屍狀態(zombie)
T:跟蹤狀態(Traced)
B:進程正在等待更多的記憶體頁
C(cpu usage):cpu利用率的估算值
清除ZOMBIE(殭屍)進程可以使用如下方法:
1> kill –18 PPID (PPID是其父進程)
這個訊號是告訴父進程,該子進程已經死亡了,請收回分配給他的資源。
2>如果不行則看能否終止其父進程(如果其父進程不需要的話)。先看其父進程又無其他子進程,如果有,可能需要先kill其他子進程,也就是兄弟進程。方法是:
kill –15 PID1 PID2(PID1,PID2是殭屍進程的父進程的其它子進程)。
然後再kill父進程:kill –15 PPID
這樣殭屍進程就可能被完全殺掉了。