獲取 Linux 系統和 Docker 容器的內存使用狀況

最近,我開始監控咱們一直在開發的 Node.js 應用程序。一段時間後,我發現它的內存使用率增加緩慢,3 天就增加了 20%。在如下 Node.js 代碼中測量了內存使用狀況。docker

const os = require("os");

const total = os.totalmem();
const free = os.freemem();
const usage = ((free - total) / total) * 100;

因此,它們基本上來自操做系統,在這種狀況下是Docker 上的Alpine Linux。幸運的是,我還記錄了應用程序進程的內存使用狀況,但它們並無增長。那麼爲何操做系統內存使用量會增長呢?緩存

緩衝區和緩存內存

我使用了top命令Shift+m(按內存使用狀況排序)並比較了長時間運行的服務器上的進程和新部署的服務器上的進程。雙方的流程幾乎相同。惟一的區別是,buffers而且cached Mem在長期運行的狀況下很高。服務器

通過一些研究或谷歌搜索後,我得出結論,這不是問題。當應用程序進程要求更多內存時,大部分buffers和cached Mem被放棄。網絡

其實free -m命令提供了一行used,並free採起緩衝區和緩存的考慮。app

$ free -m
             total  used  free  shared  buffers cached
Mem:          3950   285  3665     183       12    188
-/+ buffers/cache:    84  3866
Swap:         1896     0  1896

那麼,它們到底是什麼?根據的手冊/proc/meminfo,這是一個僞文件和 的數據源free,top還有朋友:ui

Buffers %lu
       Relatively temporary storage for raw disk blocks that
       shouldn't get tremendously large (20MB or so).

Cached %lu
       In-memory cache for files read from the disk (the page
       cache).  Doesn't include SwapCached.

我仍然不肯定到底Buffers包含什麼,但它包含文件的元數據等,並且它的大小相對微不足道。Cached包含緩存的文件內容,稱爲頁面緩存。操做系統保留頁面緩存,而 RAM 有足夠的可用空間。這就是爲何即便進程沒有泄漏內存,內存使用量也在增長。操作系統

若是您有興趣,/proc/meminfo 輸出中的 Buffers 和 Cached 列有什麼區別?在 Quora 上有關於Buffers和的更多詳細信息Cached。code

可用內存

那麼,咱們應該使用free + buffers + cached? /proc/meminfo有一個更好的指標,稱爲MemAvailable。排序

MemAvailable %lu (since Linux 3.14)
       An estimate of how much memory is available for
       starting new applications, without swapping.
$ cat /proc/meminfo
MemTotal:        4045572 kB
MemFree:         3753648 kB
MemAvailable:    3684028 kB
Buffers:           13048 kB
Cached:           193336 kB
...

它的背景在 Linux Kernel中的提交中獲得了很好的解釋,但本質上它排除了不可釋放的頁面緩存幷包括可回收的平板內存。Linux v4.12-rc2 中的當前實現看起來仍然幾乎相同。進程

free -m有available列的一些實現。例如,在 Boot2Docker 上:

$ free -m
       total  used  free  shared  buff/cache  available
Mem:    3950    59  3665     183         226       3597
Swap:   1896     0  1896

它也能夠經過--mem-avail標誌在 AWS CloudWatch 指標上使用。

關於 Docker 的一些背景

個人另外一個問題是「Docker 中的這些指標是否相同?」。在深刻探討這個問題以前,讓咱們檢查一下 docker 是如何工做的。

根據Docker 概述:底層技術,Docker 容器中的進程直接在其主機操做系統中運行,沒有任何虛擬化,但因爲這些 Linux 內核特性,它們與主機操做系統和其餘容器有效隔離:

命名空間:隔離 PID、主機名、用戶 ID、網絡訪問、IPC 等。

  • cgroups:限制資源使用
  • UnionFS : 隔離文件系統
    因爲命名空間的緣由,pscommand除了列出宿主操做系統中的其餘進程外,還列出了Docker容器的進程,而它不能列出宿主操做系統或docker容器中其餘容器的進程。

默認狀況下,Docker 容器沒有資源限制。因此,若是你在一臺主機上運行一個容器,而且不限制容器的資源使用,這就是個人狀況,容器的「空閒內存」與主機操做系統的「空閒內存」是同樣的。

Docker 容器上的內存指標

若是您想從容器外部監控 Docker 容器的內存使用狀況,這很容易。您可使用docker stats.

$ docker stats
CONTAINER     CPU %  MEM USAGE / LIMIT  MEM %  NET I/O     BLOCK I/O  PIDS
fc015f31d9d1  0.00%  220KiB / 3.858GiB  0.01%  1.3kB / 0B  0B / 0B    2

可是,若是您想獲取容器中的內存使用狀況或獲取更詳細的指標,就變得複雜了。Linux 容器內的內存詳細描述了困難。

/proc/meminfo和sysinfo,由Node.js使用os.totalmem()和使用os.freemem(),不是孤立的,若是您在 Docker 容器中使用top和等普通實用程序,您將得到主機操做系統的指標free。

要獲取特定於 Docker 容器的指標,您能夠在/sys/fs/cgroup/memory/. 不過,它們並未根據Linux 容器內的內存進行標準化。

$ cat /sys/fs/cgroup/memory/memory.usage_in_bytes
303104
$ cat /sys/fs/cgroup/memory/memory.limit_in_bytes
9223372036854771712

memory.limit_in_bytes若是沒有限制,則返回一個很是大的數字。在這種狀況下,您可使用/proc/meminfo或使用它的命令找到主機操做系統的總內存。

結論

這是一段比我最初想象的更長的旅程。個人要點是:

  • Available Memory > Free Memory 即: 容許使用內存 > 空閒內存
  • 能用MemAvailable時,用MemAvailable
  • Docker 容器中的進程直接在主機操做系統中運行
  • 準確瞭解您正在測量的內容,尤爲是在 Docker 容器中
相關文章
相關標籤/搜索