線(xiàn)上服務(wù)OOMkill根因竟是PageCache的問(wèn)題


問(wèn)題背景&現(xiàn)象

ExitCode:137 OOMkill

問(wèn)題現(xiàn)象137.png

線(xiàn)上環(huán)境的后臺(tái)服務(wù)頻繁重啟绣张,重啟的原因日志是ExitCode:137 OOMkill 。OOMkill是服務(wù)器的一種保護(hù)行為花椭,服務(wù)器會(huì)定時(shí)的掃描服務(wù)器中的各個(gè)進(jìn)程,每個(gè)進(jìn)程根據(jù)一種機(jī)制得到一個(gè)分?jǐn)?shù),如果這個(gè)分?jǐn)?shù)最高則會(huì)被服務(wù)器主動(dòng)kill掉择同。OOMkill的具體機(jī)制在此不做過(guò)多贅述赁濒。而進(jìn)程得到高分的原因一般情況是內(nèi)存資源占用過(guò)高導(dǎo)致的轨奄。被OOMkill后總是難于保留當(dāng)時(shí)具體情況,每次都是服務(wù)被重啟了才發(fā)現(xiàn)問(wèn)題拒炎。還好運(yùn)維平臺(tái)可以支持OOMkill保護(hù)挪拟,發(fā)現(xiàn)資源超限情況不讓直接OOMkill而是先保護(hù)現(xiàn)場(chǎng)并發(fā)出告警。

Memory hit original limit

Memory hit original limit告警.png

果然設(shè)置了保護(hù)之后击你,告警就接踵而至了玉组。而且確實(shí)是內(nèi)存超限導(dǎo)致的,如果沒(méi)有保護(hù)又事一次煩人的OOMkill 丁侄。知道是內(nèi)存的問(wèn)題接下來(lái)問(wèn)題定位的方向就更明了了惯雳。


問(wèn)題定位&分析

先dump堆內(nèi)存再說(shuō)

第一個(gè)首先懷疑的是應(yīng)用服務(wù)的堆內(nèi)存。但是dump堆內(nèi)存下來(lái)分析后鸿摇,發(fā)現(xiàn)占用的并不高石景。總內(nèi)存只有200M左右拙吉。


3.堆內(nèi)存分析.png

看來(lái)堆內(nèi)存并不是罪魁禍?zhǔn)住?br> 總結(jié):dump命令潮孽,jmap -dump:format=b,file= /文件路徑/dump文件名稱(chēng).hprof 進(jìn)程ID ,如:jmap -dump:format=b,file=/home/heap.hprof 1

是堆外內(nèi)存的原因嗎庐镐?

不是堆內(nèi)存恩商,那應(yīng)該就是堆外內(nèi)存的原因了。項(xiàng)目中有些開(kāi)源框架使用到Netty必逆,Netty是有使用堆外內(nèi)存的怠堪。而且JDK8的元空間也是屬于堆外。

JDK8元空間觀測(cè)

通過(guò)查看JVM的配置名眉,發(fā)現(xiàn)元空間的大小并沒(méi)有限制粟矿。


4元空間大小沒(méi)做限制.png

原因是項(xiàng)目以前使用的是JDK8以前的版本,升級(jí)到了JDK8后對(duì)應(yīng)的JVM配置沒(méi)有對(duì)應(yīng)更新损拢。運(yùn)維平臺(tái)觀測(cè)到的非堆內(nèi)存占用確實(shí)也是不小陌粹。


image.png

給JVM參數(shù)加元空間的限制,-XX:MetaspaceSize=xxxm -XX:MaxMetaspaceSize=xxxm 福压。
本以為萬(wàn)事大吉掏秩,但過(guò)了幾天煩人的內(nèi)存超限告警還是來(lái)了或舞。

netty堆外內(nèi)存占用觀測(cè)

不是元空間占用的大量?jī)?nèi)存,那會(huì)不會(huì)是項(xiàng)目其他地方使用到了堆內(nèi)存呢蒙幻? 查看了整個(gè)項(xiàng)目的業(yè)務(wù)代碼和相關(guān)的依賴(lài)映凳,只有Netty使用到堆外內(nèi)存。那么就想辦法觀測(cè)一下Netty使用堆外內(nèi)存的情況邮破。關(guān)于Netty的堆外內(nèi)存如何使用诈豌,因篇幅有限此處不做擴(kuò)展;只是通過(guò)以下工具可以監(jiān)控到堆外內(nèi)存的大惺愫汀:

public static List<String> startReport() {
        Field field = ReflectionUtils.findField(PlatformDependent.class, "DIRECT_MEMORY_COUNTER");
        field.setAccessible(true);
        try {
            AtomicLong directMemory = (AtomicLong) field.get(PlatformDependent.class);
            int memoryInKb = (int) (directMemory.get() / 1024);
            log.info("堆外內(nèi)存大薪糜妗:{}",memoryInKb);
            if (list.size() <=100) {
                list.add("時(shí)間:" + LocalDateTime.now()
                                              .toString() + "  堆外內(nèi)存:" + memoryInKb + "k ");
            }else {
                list.clear();
            }
            return list;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return list;
    }

并通過(guò)一個(gè)上帝接口持續(xù)觀測(cè):


image.png

但是經(jīng)過(guò)一段時(shí)間的觀測(cè),占用的內(nèi)存并沒(méi)有異常增長(zhǎng)摧莽。

page cache占用總內(nèi)存情況

無(wú)奈之下庙洼,只能進(jìn)一步的通過(guò)運(yùn)維監(jiān)控平臺(tái)繼續(xù)找一些觀測(cè)數(shù)據(jù)。經(jīng)過(guò)長(zhǎng)時(shí)間的觀測(cè)對(duì)比范嘱。發(fā)現(xiàn)page cache的變化對(duì)總內(nèi)存變化影響很明顯送膳,而且發(fā)出內(nèi)存超限提醒的服務(wù)節(jié)點(diǎn)page cache都沒(méi)法正常回收丑蛤。

5pc對(duì)總內(nèi)存的影響很明顯.png

page cache是linux內(nèi)核為了提高磁盤(pán)文件操作而設(shè)計(jì)的一種機(jī)制叠聋。它會(huì)將一些磁盤(pán)的文件數(shù)據(jù)寫(xiě)入到內(nèi)存中,并設(shè)計(jì)一套淘汰機(jī)制回收內(nèi)存受裹。根據(jù)上圖觀測(cè)到的情況碌补,page cache占用的內(nèi)存并沒(méi)法正常回收棉饶。

vmtouch觀測(cè)文件緩存情況

梳理了整個(gè)業(yè)務(wù)項(xiàng)目的代碼厦章,并沒(méi)有發(fā)現(xiàn)有大量讀寫(xiě)文件的地方。懷疑是日志文件的讀寫(xiě)照藻,導(dǎo)致一直在產(chǎn)生page cache袜啃。為了驗(yàn)證個(gè)問(wèn)題需要使用到vmtouch命令,關(guān)于此命令的介紹可以參見(jiàn)官方文檔:https://hoytech.com/vmtouch
此命令可以查看磁盤(pán)文件被加載到內(nèi)存中的情況幸缕。
查看日志文件被加載到內(nèi)存的情況:

image.png

整個(gè)日志文件900M左右群发,全部被加載到內(nèi)存中。
將被加載到內(nèi)存中的緩沖驅(qū)逐掉:
image.png

觀測(cè)到的page cache和總內(nèi)存對(duì)應(yīng)馬上降低下來(lái):
image.png

終于問(wèn)題原因變得明朗了发乔,接下來(lái)就要看看page cache為什么不能正呈旒耍回收了。

page cache數(shù)據(jù)觀測(cè)

為什么page cache這么多栏尚?

page cache為什么這么多起愈,是因?yàn)槿罩疚募罅藛幔繛榱蓑?yàn)證這個(gè)問(wèn)題,通過(guò)修改log4j的配置抬虽,將每個(gè)日志文件分割成500M以?xún)?nèi)官觅,但是問(wèn)題依舊。而且日志文件被切割后阐污,不再寫(xiě)入的日志文件在依然被加載到內(nèi)存中缰猴,說(shuō)明是讀日志文件的原因。


企業(yè)微信截圖_16235175941830.png
企業(yè)微信截圖_16235176181799.png

日志文件的讀場(chǎng)景疤剑,是運(yùn)維平臺(tái)做日志采集的情況才會(huì)觸發(fā)的。于是找了運(yùn)維平臺(tái)的同事反饋闷堡。

為什么page cache沒(méi)正嘲欤回收?

反饋問(wèn)題后自己也持續(xù)觀察杠览,發(fā)現(xiàn)有問(wèn)題的節(jié)點(diǎn)弯菊。發(fā)現(xiàn)page cache的掃描速度很慢,而且臟頁(yè)閾值配置的也不一樣踱阿。和運(yùn)維同事溝通后管钳,得知服務(wù)器節(jié)點(diǎn)是被隨機(jī)分配的,可能節(jié)點(diǎn)屬于不同的物理機(jī)软舌,而臟頁(yè)閾值的配置使用的應(yīng)該是物理機(jī)的配置才漆。


![企業(yè)微信截圖_16235191045039.png](https://upload-images.jianshu.io/upload_images/3424555-9f22f5cf599b0d7e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

問(wèn)題解決&防范

曲線(xiàn)救國(guó)

既然問(wèn)題原因是讀日志文件導(dǎo)致的,那就不讓監(jiān)控程序主動(dòng)來(lái)讀取日志佛点,而是主動(dòng)將數(shù)據(jù)通過(guò)消息隊(duì)列推送給監(jiān)控系統(tǒng)醇滥。公司基于log4j自研封裝了日志工具,可以根據(jù)配置將日志直接通過(guò)kafka推送給監(jiān)控系統(tǒng)超营,這樣就能避免讀日志文件鸳玩,page cache的問(wèn)題也可以避免了。

問(wèn)題根治

主動(dòng)推送日志的方法只能是避免問(wèn)題的發(fā)生演闭,要根治問(wèn)題還是得從page cache的相關(guān)配置入手不跟。page cache難回收的原因一般有三個(gè)(具體可以參見(jiàn):Page Cache難以回收問(wèn)題):
1.直接內(nèi)存回收導(dǎo)致
2.系統(tǒng)臟頁(yè)內(nèi)存積壓過(guò)多導(dǎo)致
3.系統(tǒng)NUMA策略配置不當(dāng)導(dǎo)致
其中情況1 通過(guò)sar -B命令觀測(cè)可以排插,因?yàn)閜gscand并沒(méi)有發(fā)生

企業(yè)微信截圖_16235198212630.png

情況3通過(guò)命令numactl --hardware確認(rèn)也可以排除了米碰。
情況2需要不斷配置系統(tǒng)參數(shù)并調(diào)試窝革,因是線(xiàn)上環(huán)境,而且初始環(huán)境沒(méi)法模擬驗(yàn)證见间,只能反饋給運(yùn)維團(tuán)隊(duì)聊闯,讓他們持續(xù)優(yōu)化。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末米诉,一起剝皮案震驚了整個(gè)濱河市菱蔬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖拴泌,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件魏身,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蚪腐,警方通過(guò)查閱死者的電腦和手機(jī)箭昵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)回季,“玉大人家制,你說(shuō)我怎么就攤上這事∨菀唬” “怎么了颤殴?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)鼻忠。 經(jīng)常有香客問(wèn)我涵但,道長(zhǎng),這世上最難降的妖魔是什么帖蔓? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任矮瘟,我火速辦了婚禮,結(jié)果婚禮上塑娇,老公的妹妹穿的比我還像新娘澈侠。我一直安慰自己,他們只是感情好埋酬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布埋涧。 她就那樣靜靜地躺著,像睡著了一般奇瘦。 火紅的嫁衣襯著肌膚如雪棘催。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天耳标,我揣著相機(jī)與錄音醇坝,去河邊找鬼。 笑死次坡,一個(gè)胖子當(dāng)著我的面吹牛呼猪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播砸琅,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼宋距,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了症脂?” 一聲冷哼從身側(cè)響起谚赎,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤淫僻,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后壶唤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體雳灵,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年闸盔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了悯辙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡迎吵,死狀恐怖躲撰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情击费,我是刑警寧澤茴肥,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站荡灾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瞬铸。R本人自食惡果不足惜批幌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嗓节。 院中可真熱鬧荧缘,春花似錦、人聲如沸拦宣。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鸵隧。三九已至绸罗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間豆瘫,已是汗流浹背珊蟀。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留外驱,地道東北人育灸。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像昵宇,于是被迫代替她去往敵國(guó)和親磅崭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容