今天下午網站宕了兩次機,發工單給阿里雲,發現原因是伺服器的CPU 100%了。
重啟伺服器後,使用 top 命令看看是哪些進程消耗那麼大的 CPU 使用。盯了有好十幾分鐘,主要消耗 CPU 的進程有兩個,一個是 mysql,另一個是 apache。下面的圖可以看到,mysql 佔用了很大部分的 CPU 使用。apache 單個進程雖然佔得不多,但有不少個 apache 進程同時存在,也消耗了不少 CPU 的使用。
當然,這些不足以讓伺服器的 CPU 直接跑滿掛掉,後來發現了兩個大傢伙:
當 mysql 的 CPU 限定降下來之後,出現了兩個奇怪的進程:kswapd0 和 events/0。
1. kswapd0
Linux uses kswapd for virtual memory management such that pages that have been recently accessed are kept in memory and less active pages are paged out to disk.
(what is a page?)…Linux uses manages memory in units called pages.
So,the kswapd process regularly decreases the ages of unreferenced pages…and at the end they are paged out(moved out) to disk
kswapd0進程的作用:它是虛擬記憶體管理中,負責換頁的,作業系統每過一定時間就會喚醒kswapd ,看看記憶體是否緊張,如果不緊張,則睡眠,在 kswapd 中,有2 個閥值,pages_hige 和 pages_low,當空閑記憶體頁的數量低於 pages_low 的時候,kswapd進程就會掃描記憶體並且每次釋放出32 個free pages,直到 free page 的數量到達pages_high。
查看記憶體使用量率,發現記憶體確實不夠用,有時候已經使用到了swap。
2. events/0
另一個進程 events/0 是工作者線程,主要是用來執行delay work的。先簡單介紹一下。
我們都知道中斷的底半部機制有三種:非強制中斷、tasklet和工作隊列。其中非強制中斷很少使用,核心中只有網路在使用,它的延時是最小的。
tasklet是非強制中斷的一個應用,所有線程註冊的tasklet都會順序被執行。因此tasklet的執行環境是非強制中斷上下文,所以不能阻塞或者睡眠。一般情況下,tasklet的延遲也很小,可以滿足大部分需求。
要是底半部中可能睡眠,那麼只好使用工作隊列了。工作隊列其實是把要做的底半部的函數交給核心的專門線程去調用。這樣工作隊列就運行於線程環境了,不怕睡眠。當然,睡眠會影響註冊到同一線程的其它底半部的執行,但不會引起大的問題。每個CPU都有一個線程(events/n,n是編號)負責執行工作隊列,第一個CPU的線程是events/0,如果是雙核的,還會有一個events/1線程。程式使用了工作隊列,所以每次執行都會多出一個events/0(第一個CPU上背景工作執行緒)。
核心的非強制中斷輔助處理線程ksoftirqd/n(n是CPU編號),它們負責出發非強制中斷中觸發的非強制中斷。它們將重新觸發非強制中斷放在系統空閑時調用,而不是馬上。這樣使用者空間不至於饑餓,重新觸發的非強制中斷也得以儘快執行。(《Linux核心設計與實現》85頁)
宕機原因顯而易見了,physical mem 不足,引起 swap 頻繁。其實這也是 VPS 使用上的一個常見的問題了,通常是由 Apache 佔用記憶體過多引起的。kswapd0 是系統的虛擬記憶體管理程式,如果實體記憶體不夠用,系統就會喚醒 kswapd0 進程,由 kswapd0 分配磁碟交換空間作緩衝,因而佔用大量的 CPU 資源。重啟Apache,釋放記憶體,問題就會消失。但這不是長久之計,最好的方法還是花點錢升級下記憶體。我也知道隨著訪問量的不斷上漲,肯定要升級下記憶體,但是沒想到這個問題這麼快就來了……