cgroup內(nèi)存限制不起作用的原因
作者:禹鼎侯
來源:SegmentFault 思否
今天遇到一個cgroup資源限制時,內(nèi)存限制不起作用的問題。一開始,對進(jìn)程的cgroup設(shè)置最大內(nèi)存限制為10M,但運(yùn)行了幾分鐘以后,內(nèi)存明顯飆上去了,甚至達(dá)到了20多M。
情景還原
在memory.limit_in_bytes中設(shè)置如下:

10485760表示的是字節(jié)數(shù),也就是等于 1024 * 1024 * 10 = 10M。
運(yùn)行一段時間后,查看實(shí)際使用的內(nèi)存,memory.usage_in_bytes文件中數(shù)值如下:

可以看到,確實(shí)拿捏得死死的,看起來似乎內(nèi)存限制成功了,沒有什么問題。
可是當(dāng)使用top命令去查看的時候,卻發(fā)現(xiàn)已經(jīng)內(nèi)存消耗已高達(dá)23M左右,這明顯不正常。

使用前臺監(jiān)控界面查看,得到的是同樣的結(jié)果:

可見,雖然設(shè)置了cgroup,而且看起來似乎是生效了,但實(shí)際上并沒有限制住。
問題排查
因?yàn)樵摮绦虻馁Y源限制是利用agent代理程序去做的,并非人為去操作,所以一開始懷疑該進(jìn)程沒有加入cgroup資源限制策略,查看之后排除了這一可能性。
第一步查到進(jìn)程PID以及其相應(yīng)的線程ID,如下所示:

然后查看tasks里面加入的進(jìn)程號,如下:

可以看到,該進(jìn)程所有的進(jìn)程和線程號都被加入到了cgroup中。因此,并不是這個引起的。
然后就想到會不會是使用了swap內(nèi)存,可以看到,8G的swap內(nèi)存已經(jīng)被使用了24M,看起來有點(diǎn)像。

為了驗(yàn)證這一猜想,我把進(jìn)程先給停掉了,然后查看swap內(nèi)存使用情況:

可以看到,flow進(jìn)程停掉之后,swap內(nèi)存一下子從24M降到了20K,看樣子就是這個東西搞的鬼。
于是我查看了一下memory.swappiness,這個數(shù)值居然達(dá)到了30,看來是這個問題沒跑了。

問題解決
知道了問題所在,解決也就比較簡單了。首先第一步,把memory.swappiness設(shè)為0。
$ echo 0 > memory.swappiness
然后重新啟動進(jìn)程,這次成功了,當(dāng)內(nèi)存剛剛達(dá)到10M,直接就被kill掉了。
但實(shí)際上,我并不希望這個進(jìn)程就如此簡單粗暴的被殺掉,考慮到memory.oom_control可以設(shè)置內(nèi)存達(dá)到限制后的處理措施,oom_kill_disable為0代表內(nèi)存超過限制就殺掉進(jìn)程,oom_kill_disable為1則代表繼續(xù)等待,當(dāng)有內(nèi)存釋放時,繼續(xù)申請內(nèi)存。總而言之,就是不會把進(jìn)程殺掉。

所以,將oom_kill_disable設(shè)置為1后重啟程序,該問題得以解決。
總結(jié)
cgroup是Linux系統(tǒng)內(nèi)核提供的一種資源限制的策略,使用起來十分方便。鼎鼎大名的Docker容器就是基于此技術(shù),平時工作中對這種技術(shù)缺乏鉆研和積累,只知道簡單的使用,并沒有深入研究每個參數(shù)到底代表什么,其內(nèi)部原理又是什么,所以才有了遇到這種問題耗時耗力的情況。
比如memory.swappiness中從數(shù)值代表什么意思,為啥設(shè)置為0之后cgroup就起作用了?原來的30又代表什么?
通過查資料后,了解到memory.swappiness中的數(shù)值其實(shí)并不是確切的數(shù)值,而是代表了進(jìn)程使用swap空間的一個權(quán)重,該數(shù)值范圍從0-100。100表示積極使用swap,0表示優(yōu)先使用內(nèi)存。

