容器內存相關知識

這篇文章是我研究容器內存整理出的相關內容. 前後內容並沒有上下文關係, 每個知識點都可以單獨查看.

內存控制

使用這樣的命令啓動一個容器docker run -d -m 300M xxx. 可以限制容器使用的內存最大爲300M. 那麼docker是如何實現容器的內存限制呢?

其實是操作系統已經做好了支持. Linux中實現容器的兩大技術是:

  • namespace: 使用不同的命名空間實現資源的隔離. 包括:
    • PID: 進程隔離
    • Net: 網絡環境隔離
    • VFS: 文件系統隔離
    • IPC: 進程通信隔離
    • 等等, 可查看維基百科
  • cgroups: 實現對進程資源的限制. 包括: cpu/內存/最大進程數量等等. 詳情可查看官方文檔

好, namespace實現了多個容器間不同進程的隔離, cgroups實現了對單個容器的資源限制. 就是這兩個技術支撐了容器化的實現.

要查看一個進程的cgroups限制, 可查看文件/proc/<pid>/cgroup. 如果是一個容器進程, 你會看到類似於這樣的內容:

...
10:memory:/docker/<docker_id>
9:cpuset:/docker/<docker_id>
8:blkio:/docker/<docker_id>
...

將限制指向了一個路徑, 這個路徑存放在/sys/fs/cgroup這裏, 比如memory的限制路徑爲: /sys/fs/cgroup/memory/docker/<docker_id>. 在這裏能夠看到對此進程的所有內存限制. 其中每個文件的含義在官方文檔中也有說明.

至於具體的原理, 這裏不做深究.

這裏額外說一點, /sys/fs/cgroup是一個樹形結構, 子控制組的資源限制必定小於等於父控制組.

OOM Kill

如果一個進程的內存使用超過了限制, 會發生什麼呢?

隨便寫一個腳本實驗一下, 就會發現進程突然消失了, 被操作系統殺掉了.

使用docker inspect命令查看, 發現OOMKilled的值爲true. 或者直接查看系統日誌/sys/log/message也能夠看到進程被殺掉的log.

Page Cache

我們可能會碰到這樣奇怪的現象, 容器的內存限制爲200M, 且已經使用200M內存, 此時再啓動一個進程申請20M內存仍然成功, 且申請後總的內存仍然是200M.

造成這個奇怪現象的原因, 是因爲在調用函數read讀取文件的時候, 會將文件臨時存放在內存中, 以加速後續讀取. 我們使用free命令查看時, 其中的buff/cache就是文件的緩存, RSS則是實際使用的物理內存, VIRT則是進程申請的虛擬內存. 某個進程的具體內存分佈可查看文件proc/<pid>/smaps.

容器RSSbuff/cache的和, 就是容器實際使用的物理內存總值. 應該與cgroup路徑下的memory.usage_in_bytes值相同. (容器的內存分佈也可以查看文件memory.stat)

這麼一說, 這個奇怪的現象是不是就可以解釋了? 當內存不足的時候, 系統會回收文件緩存以供進程使用.

交換內存

如果容器開啓了交換內存, 你就會驚奇的發現, memory cgroup限制失效了. 容器申請了超過限制的內存仍然可以繼續執行, 只不過部分內存被交換到磁盤上了.

如果同時又Page Cache和交換內存, 操作系統優先選擇哪一個呢? 可以通過修改memory.swappiness的值來修改優先級, 其值爲0-100, 值越大, 使用交換內存的概率越大. 當值爲100時, 則Page Cache與叫換內存的概率相同. 官網介紹

不過一般啓動容器的時候, 都是將swap關閉的, 應該沒什麼需要開啓的場景吧.


還有一些內存相關的其他知識點, 大部分都可查看memory group官方文檔

原文地址: https://hujingnb.com/archives/865

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章