POD為什么會OOM


應用運行在k8s平台上,有時候會發現POD自動重啟造成業務影響,通過kubectl describe pod可以看到POD重啟的原因,如果是OOM killed,則是因為應用使用內存超過了limit,被OOM killed了。

 

其實,應用被OOM killed應該分為兩種情況:

1. POD OOM killed;

2. 宿主機內存不足,跑在宿主機上的進程被OOM killed;

 

這篇文章只討論第一種情況。

 

其實我們在定義POD的時候,可以通過resource requests及limits值,定義POD的資源需求。

 

根據requests和limits值,POD的QoS分為三種類型:

Guaranteed - 如果POD中所有容器的所有resource的limit等於request且不為0,則這個POD的QoS class就是Guaranteed;

Best-Effort - 如果POD中所有容器的所有resource的request和limit都沒有賦值,則這個POD的QoS class就是Best-Effort;

Burstable - 以上兩種情況之外就是Burstable了,通常也是畢竟普遍的配置;

 

這三種QoS分別會有什么待遇呢?因為cpu不是一種hard limit,cpu到達上限之后會被限制,但不會引起進程被殺;這里我們主要看Memory,可以簡單這樣理解:

Guaranteed - 優先級最高,它能夠確保不達到容器設置的Limit一定不會被殺。當然,如果連宿主機都OOM的話,宿主機也是會根據評分選擇性殺進程;

Best-Effort - 優先級最低,如果系統內存耗盡,該類型的POD中的進程最先被殺;

Burstable - 在系統存在內存瓶頸時,一旦內存超過他們的request值並且沒有Best-Effort類型的容器存在,這些容器就先被殺掉,當然,內存到達limit時也會被殺;

 

不管是哪種QoS的POD,如果內存使用量持續上漲,都是有可能被OOM killed的。

 

對於跑在POD里面的應用來說,就是應用重啟了,因為POD被殺之后k8s會自動重新拉起一個新的。

如果應用被莫名重啟並且應用無任何報錯,可以到監控頁面查看kube_pod_memory_working_set,確認POD內存是否已超過limit值。

 

但有的用戶有時會有疑問,為什么ps看到進程使用的rss內存跟POD監控看到的內存使用量不一致呢?

 

我們先看一下POD的內存占用包括了什么?

POD的內存控制其實是利用了Linux內核的cgroup實現的,POD的內存其實也就是cgroup的內存。這個cgroup下的進程通常包括:

1. k8s基礎容器pause進程,但這個很小,通常只占幾百kb內存;

2. 如果應用是通過shell腳本啟動的,都會有一個shell進程,但這個也不會占太多內存;

3. 應用進程(比如java, python等),主要還是這個進程占用的內存比較大;

 

另外有一點需要注意的是,POD是否OOM是以cgroup的memory.usage_in_bytes為判斷依據的,它跟ps進程看到的rss有以下差別:

memory.usage_in_bytes = total_cache + total_rss

以上數據可以在宿主機/sys/fs/cgroup/memory/kubepods/[burstable] | [besteffort]/pod<pod id>/目錄下的memory.usage_in_bytes和memory.stat中查到。

可以簡單理解為POD內存占用包括進程使用的rss和cache,如果進程使用的cache太大(如打開了大文件,比如日志)也會引起OOM killed。

 

假如應用有輸出日志並且日志文件是按時間進行切割的,那么在POD的內存監控圖中,會看到當日志文件切割時,POD的內存占用會有一個很陡峭的下降。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM