1.問題起源
有一批虛擬機(jī)都是4C8G規(guī)格的幔嗦,上面都運(yùn)行著數(shù)據(jù)庫或者mq谒养,kafka等程序,偶爾會(huì)出現(xiàn)個(gè)別組件失聯(lián)的情況身隐,使用SSH登錄的時(shí)候異常的慢廷区,即便登錄進(jìn)去了一條命令也得卡十幾秒才能執(zhí)行完,使用top查看時(shí)發(fā)現(xiàn)有一個(gè)叫kswapd0的進(jìn)程占用了大量CPU資源贾铝,而且磁盤等待(wa)特別高隙轻。
從上圖中可以看到,cpu總占用率在40%左右垢揩,磁盤等待在43%上下浮動(dòng)玖绿,cpu的大量的時(shí)間都在等待磁盤完成IO操作,可見有程序在頻繁的請求IO水孩,而下面光是kswapd0一個(gè)進(jìn)程就吃滿了一個(gè)核心镰矿,pid還是如此靠前的41,由此可見這是一個(gè)系統(tǒng)級進(jìn)程俘种。
2.虛心求教
我查閱了大量資料秤标,發(fā)現(xiàn)該程序來源于虛擬內(nèi)存,是系統(tǒng)常駐進(jìn)程宙刘,專門負(fù)責(zé)內(nèi)存換頁苍姜,cpu會(huì)定時(shí)喚醒該進(jìn)程檢查內(nèi)存使用情況,當(dāng)內(nèi)存中的空閑頁低于pages_low的時(shí)候悬包,該進(jìn)程會(huì)掃描內(nèi)存衙猪,將長久不用的內(nèi)存數(shù)據(jù)轉(zhuǎn)移到磁盤空間上,待程序需要使用這部分時(shí)再將其搬回物理內(nèi)存供程序使用布近,他每次會(huì)在物理內(nèi)存中清理32個(gè)free內(nèi)存頁垫释,一直清理直到free內(nèi)存頁的數(shù)量大于pages_high的時(shí)候停止。這兩個(gè)參數(shù)都是內(nèi)核參數(shù)撑瞧,目前沒看到可以在哪里設(shè)置這兩個(gè)參數(shù)棵譬。
有文章說pages_low、pages_high的值是在函數(shù)void setup_per_zone_pages_min(void)中進(jìn)行設(shè)置的预伺,這個(gè)函數(shù)位于mm\page_alloc.c之中订咸。(這段話我看懂了,但是我找不到這個(gè)函數(shù)酬诀,因?yàn)槲也粫?huì)看linux源碼脏嚷,對c的了解也只是一點(diǎn)點(diǎn))
總之我們可以看出一點(diǎn),如果物理內(nèi)存不足瞒御,系統(tǒng)就會(huì)陷入調(diào)用kswapd0來換頁清理內(nèi)存但內(nèi)存不足導(dǎo)致一直清理不出能達(dá)到pages_high頁數(shù)的內(nèi)存頁進(jìn)而一直清理內(nèi)存的困境父叙。也正是如此才導(dǎo)致磁盤IO與CPU居高不下。
3.問題查明
所以其實(shí)問題原因在于內(nèi)存不足,但我使用free命令排查了內(nèi)存之后發(fā)現(xiàn)問題更詭異了起來高每。
明明顯示還有4.8G內(nèi)存屿岂,為什么還是會(huì)出現(xiàn)kswapd0進(jìn)程呢?明明還有4.8G內(nèi)存鲸匿,為什么可用內(nèi)存只室常可憐的幾百KB了呢?
此時(shí)我靈光一現(xiàn)带欢,想到去排查系統(tǒng)參數(shù)运授,果不其然讓我發(fā)現(xiàn)了一個(gè)很關(guān)鍵的參數(shù)
vm.min_free_kbytes
。該參數(shù)表示linux系統(tǒng)最低會(huì)保留多少空閑內(nèi)存乔煞,當(dāng)可用內(nèi)存小于這個(gè)參數(shù)時(shí)吁朦,系統(tǒng)會(huì)觸發(fā)cache回收內(nèi)存,同樣包括觸發(fā)kswapd0程序進(jìn)行內(nèi)存換頁渡贾。該參數(shù)的單位是KB逗宜。
這個(gè)參數(shù)在這臺(tái)8G內(nèi)存的虛擬機(jī)上配置是4096000,高達(dá)3.9G空骚。
所以free內(nèi)存雖然顯示4.8G纺讲,但這個(gè)4.8G中有3.9G是系統(tǒng)保留的,不允許使用的囤屹,真正可用的內(nèi)存只剩幾百M(fèi)B熬甚,系統(tǒng)自然會(huì)開始回收內(nèi)存。
官方建議是這個(gè)配置項(xiàng)的值在物理內(nèi)存的0.4%~5%之間肋坚,對于總物理內(nèi)存低于32G的機(jī)器來說乡括,不建議配置此項(xiàng),默認(rèn)值即可智厌。
4.額外的內(nèi)容
vm.min_free_kbytes所保留的內(nèi)存會(huì)在可用的物理內(nèi)存被占滿之后讓系統(tǒng)運(yùn)行MMU(內(nèi)存管理單元)用的诲泌,好讓系統(tǒng)可以清理內(nèi)存,如果設(shè)置的過小铣鹏,比如小于4096敷扫,那么系統(tǒng)則很容易崩潰,因?yàn)檫@會(huì)導(dǎo)致MMU無法運(yùn)行吝沫。
該選項(xiàng)的默認(rèn)值是45056呻澜,也就是45M递礼。