linux內存監控
要明白docker容器內存是如何計算的,首先要明白linux中內存的相關概念。
使用free命令可以查看當前內存使用情況。
[root@localhost ~]$ free
total used free shared buffers cached
Mem: 264420684 213853512 50567172 71822688 2095364 175733516
-/+ buffers/cache: 36024632 228396052
Swap: 16777212 1277964 15499248
這里有幾個概念:
- mem: 物理內存
- swap: 虛擬內存。即可以把數據存放在硬盤上的數據
- shared: 共享內存。存在在物理內存中。
- buffers: 用於存放要輸出到disk(塊設備)的數據的
- cached: 存放從disk上讀出的數據
可以參考這里。
為方便說明,我對free的結果做了一個對應。
[root@localhost ~]$ free
total used free shared buffers cached
Mem: total_mem used_mem free_mem shared_mem buffer cache
-/+ buffers/cache: real_used real_free
Swap: total_swap used_swap free_swap
| 名稱 | 說明 |
|---|---|
| total_mem | 物理內存總量 |
| used_mem | 已使用的物理內存量 |
| free_mem | 空閑的物理內存量 |
| shared_mem | 共享內存量 |
| buffer | buffer所占內存量 |
| cache | cache所占內存量 |
| real_used | 實際使用的內存量 |
| real_free | 實際空閑的內存量 |
| total_swap | swap總量 |
| used_swap | 已使用的swap |
| free_swap | 空閑的swap |
一般認為,buffer和cache是還可以再進行利用的內存,所以在計算空閑內存時,會將其剔除。
因此這里有幾個等式:
real_used = used_mem - buffer - cache
real_free = free_mem + buffer + cache
total_mem = used_mem + free_mem
了解了這些,我們再來看free的數據源。其實其數據源是來自於/proc/memeinfo文件。
[root@localhost ~]$ cat /proc/meminfo
MemTotal: 264420684 kB
MemFree: 50566436 kB
Buffers: 2095356 kB
Cached: 175732644 kB
SwapCached: 123688 kB
Active: 165515340 kB
Inactive: 37004224 kB
Active(anon): 92066880 kB
Inactive(anon): 4455076 kB
Active(file): 73448460 kB
Inactive(file): 32549148 kB
Unevictable: 362900 kB
Mlocked: 74696 kB
SwapTotal: 16777212 kB
SwapFree: 15499248 kB
Dirty: 2860 kB
Writeback: 0 kB
AnonPages: 24932928 kB
Mapped: 58165040 kB
Shmem: 71822688 kB
Slab: 8374496 kB
SReclaimable: 8163096 kB
SUnreclaim: 211400 kB
KernelStack: 45824 kB
PageTables: 606296 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 148987552 kB
Committed_AS: 114755628 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 772092 kB
VmallocChunk: 34225428328 kB
HardwareCorrupted: 0 kB
AnonHugePages: 22083584 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 7168 kB
DirectMap2M: 2015232 kB
DirectMap1G: 266338304 kB
docker
說完linux的內存,我們再來看下docker的內存監控。docker自身提供了一種內存監控的方式,即可以通過docker stats對容器內存進行監控。
該方式實際是通過對cgroup中相關數據進行取值從而計算得到。
cgroup
cgroup中的memory子系統為hierarchy提供了如下文件。
[root@localhost ~]$ ll /cgroup/memory/docker/53a11f13c08099dd6d21030dd2ddade54d5cdd7ae7e9e68f5ba055ad28498b6f/
總用量 0
--w--w--w- 1 root root 0 2月 22 12:51 cgroup.event_control
-rw-r--r-- 1 root root 0 5月 25 17:07 cgroup.procs
-rw-r--r-- 1 root root 0 2月 22 12:51 memory.failcnt
--w------- 1 root root 0 2月 22 12:51 memory.force_empty
-rw-r--r-- 1 root root 0 3月 30 17:06 memory.limit_in_bytes
-rw-r--r-- 1 root root 0 2月 22 12:51 memory.max_usage_in_bytes
-rw-r--r-- 1 root root 0 2月 22 12:51 memory.memsw.failcnt
-rw-r--r-- 1 root root 0 3月 30 17:06 memory.memsw.limit_in_bytes
-rw-r--r-- 1 root root 0 2月 22 12:51 memory.memsw.max_usage_in_bytes
-r--r--r-- 1 root root 0 2月 22 12:51 memory.memsw.usage_in_bytes
-rw-r--r-- 1 root root 0 2月 22 12:51 memory.move_charge_at_immigrate
-rw-r--r-- 1 root root 0 2月 22 12:51 memory.oom_control
-rw-r--r-- 1 root root 0 3月 30 17:06 memory.soft_limit_in_bytes
-r--r--r-- 1 root root 0 2月 22 12:51 memory.stat
-rw-r--r-- 1 root root 0 2月 22 12:51 memory.swappiness
-r--r--r-- 1 root root 0 2月 22 12:51 memory.usage_in_bytes
-rw-r--r-- 1 root root 0 2月 22 12:51 memory.use_hierarchy
-rw-r--r-- 1 root root 0 2月 22 12:51 notify_on_release
-rw-r--r-- 1 root root 0 2月 22 12:51 tasks
這些文件的具體含義可以查看相關資料cgroup memory。
這里主要介紹幾個與docker監控相關的。
| 文件名 | 說明 |
|---|---|
| memory.usage_in_bytes | 已使用的內存量(包含cache和buffer)(字節),相當於linux的used_meme |
| memory.limit_in_bytes | 限制的內存總量(字節),相當於linux的total_mem |
| memory.failcnt | 申請內存失敗次數計數 |
| memory.memsw.usage_in_bytes | 已使用的內存和swap(字節) |
| memory.memsw.limit_in_bytes | 限制的內存和swap容量(字節) |
| memory.memsw.failcnt | 申請內存和swap失敗次數計數 |
| memory.stat | 內存相關狀態 |
以下為一個容器的樣例。
[root@localhost 53a11f13c08099dd6d21030dd2ddade54d5cdd7ae7e9e68f5ba055ad28498b6f]$ cat memory.usage_in_bytes
135021858816
[root@localhost 53a11f13c08099dd6d21030dd2ddade54d5cdd7ae7e9e68f5ba055ad28498b6f]$ cat memory.memsw.usage_in_bytes
135679291392
[root@localhost 53a11f13c08099dd6d21030dd2ddade54d5cdd7ae7e9e68f5ba055ad28498b6f]$ cat memory.stat
cache 134325506048
rss 695980032
mapped_file 16155119616
pgpgin 21654116032
pgpgout 21705492352
swap 655171584
inactive_anon 4218880
active_anon 74202603520
inactive_file 8365199360
active_file 52449439744
unevictable 0
hierarchical_memory_limit 137438953472
hierarchical_memsw_limit 274877906944
total_cache 134325506048
total_rss 695980032
total_mapped_file 16155119616
total_pgpgin 21654116032
total_pgpgout 21705492352
total_swap 655171584
total_inactive_anon 4218880
total_active_anon 74202603520
total_inactive_file 8365199360
total_active_file 52449439744
total_unevictable 0
memory.stat
memory.stat包含有最豐富的
| 統計 | 描述 |
|---|---|
| cache | 頁緩存,包括 tmpfs(shmem),單位為字節 |
| rss | 匿名和 swap 緩存,不包括 tmpfs(shmem),單位為字節 |
| mapped_file | memory-mapped 映射的文件大小,包括 tmpfs(shmem),單位為字節 |
| pgpgin | 存入內存中的頁數 |
| pgpgout | 從內存中讀出的頁數 |
| swap | swap 用量,單位為字節 |
| active_anon | 在活躍的最近最少使用(least-recently-used,LRU)列表中的匿名和 swap 緩存,包括 tmpfs(shmem),單位為字節 |
| inactive_anon | 不活躍的 LRU 列表中的匿名和 swap 緩存,包括 tmpfs(shmem),單位為字節 |
| active_file | 活躍 LRU 列表中的 file-backed 內存,以字節為單位 |
| inactive_file | 不活躍 LRU 列表中的 file-backed 內存,以字節為單位 |
| unevictable | 無法再生的內存,以字節為單位 |
| hierarchical_memory_limit | 包含 memory cgroup 的層級的內存限制,單位為字節 |
| hierarchical_memsw_limit | 包含 memory cgroup 的層級的內存加 swap 限制,單位為字節 |
active_anon + inactive_anon = anonymous memory + file cache for tmpfs + swap cache
active_file + inactive_file = cache - size of tmpfs
docker原生內存監控
再來說到docker原生的docker stats。其具體實現在libcontainer中可以看到。其將容器的內存監控分為cache,usage,swap usage,kernel usage,kernel tcp usage。
其中cache是從memory.stat中的cache中獲取。
usage是使用memory.usage_in_bytes和memory.limit_in_bytes進行相除來計算使用率。這一方式有一個弊端,就是不夠細化,沒有區分出cache部分,不能真正反映內存使用率。因為一般來說cache是可以復用的內存部分,因此一般將其計入到可使用的部分。
可以考慮的改進計算方式
改進方式在統計內存使用量時將cache計算排除出去。類似於linux中計算real_used時將buffer和cache排除一樣。
cache並不能直接應用memory.stat中的cache,因為其中包括了tmpfs,而tmpfs算是實際使用的內存部分。
tmpfs即share memory,共享內存
因為在memory.stat中存在有
active_file + inactive_file = cache - size of tmpfs
因此可以計算實際使用的內存量為
real_used = memory.usage_in_bytes - (rss + active_file + inactive_file)
