内存使用差异:docker 容器内的 cgroup memory.usage_in_bytes 与 RSS

Posted

技术标签:

【中文标题】内存使用差异:docker 容器内的 cgroup memory.usage_in_bytes 与 RSS【英文标题】:Memory usage discrepancy: cgroup memory.usage_in_bytes vs. RSS inside docker container 【发布时间】:2018-11-24 17:16:39 【问题描述】:

“Kubernetes”(v1.10.2)说我的 pod(包含一个容器)正在使用大约 5GB 内存。在容器内部,RSS 更像是 681MiB。任何小马都可以用以下数据解释如何从 681MiB 到 5GB(或者描述如何用我省略的另一个命令来弥补差异,无论是来自容器还是来自在 kubernetes 中运行此容器的 docker 主机)?

kubectl top pods 说 5GB:

% kubectl top pods -l app=myapp
NAME                             CPU(cores)   MEMORY(bytes)
myapp-56b947bf6d-2lcr7           39m          5039Mi

Cadvisor 报告了类似的数字(可能来自略有不同的时间,因此请忽略细微差异):

container_memory_usage_bytespod_name=~".*myapp.*"      5309456384

5309456384 / 1024.0 / 1024 ~= 5063 ~= 5039

在容器内,这个文件似乎是 cadvisor 获取数据的地方:

% kubectl exec -it myapp-56b947bf6d-2lcr7 bash
meme@myapp-56b947bf6d-2lcr7:/app# cat /sys/fs/cgroup/memory/memory.usage_in_bytes
5309456384

容器内的驻留集大小 (RSS) 不匹配(小于 1GB):

meme@myapp-56b947bf6d-2lcr7:/app# kb=$(ps aux | grep -v grep | grep -v 'ps aux' | grep -v bash | grep -v awk | grep -v RSS | awk 'print $6' | awk 's+=$1 END printf "%.0f", s'); mb=$(expr $kb / 1024); printf "Kb: $kb\nMb: $mb\n"
Kb: 698076
Mb: 681

如果有帮助,请使用完整的 ps aux:

meme@myapp-56b947bf6d-2lcr7:/app# ps aux | grep -v grep | grep -v 'ps aux' | grep -v bash | grep -v awk
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
meme         1  0.0  0.0 151840 10984 ?        Ss   Jun04   0:29 /usr/sbin/apache2 -D FOREGROUND
www-data    10  0.0  0.0 147340  4652 ?        S    Jun04   0:00 /usr/sbin/apache2 -D FOREGROUND
www-data    11  0.0  0.0 148556  4392 ?        S    Jun04   0:16 /usr/sbin/apache2 -D FOREGROUND
www-data    12  0.2  0.0 2080632 11348 ?       Sl   Jun04  31:58 /usr/sbin/apache2 -D FOREGROUND
www-data    13  0.1  0.0 2080384 10980 ?       Sl   Jun04  18:12 /usr/sbin/apache2 -D FOREGROUND
www-data    68  0.3  0.0 349048 94272 ?        Sl   Jun04  47:09 hotapp
www-data   176  0.2  0.0 349624 92888 ?        Sl   Jun04  43:11 hotapp
www-data   179  0.2  0.0 349196 94456 ?        Sl   Jun04  42:20 hotapp
www-data   180  0.3  0.0 349828 95112 ?        Sl   Jun04  44:14 hotapp
www-data   185  0.3  0.0 346644 91948 ?        Sl   Jun04  43:49 hotapp
www-data   186  0.3  0.0 346208 91568 ?        Sl   Jun04  44:27 hotapp
www-data   189  0.2  0.0 350208 95476 ?        Sl   Jun04  41:47 hotapp

来自 docker 容器统计 API 的内存部分:

curl --unix-socket /var/run/docker.sock 'http:/v1.24/containers/a45fc651e7b12f527b677e6a46e2902786bee6620484922016a135e317a42b4e/stats?stream=false' | jq . # yields:

"memory_stats": 
  "usage": 5327712256,
  "max_usage": 5368344576,
  "stats": 
    "active_anon": 609095680,
    "active_file": 74457088,
    "cache": 109944832,
    "dirty": 28672,
    "hierarchical_memory_limit": 5368709120,
    "inactive_anon": 1687552,
    "inactive_file": 29974528,
    "mapped_file": 1675264,
    "pgfault": 295316278,
    "pgmajfault": 77,
    "pgpgin": 85138921,
    "pgpgout": 84964308,
    "rss": 605270016,
    "rss_huge": 0,
    "shmem": 5513216,
    "total_active_anon": 609095680,
    "total_active_file": 74457088,
    "total_cache": 109944832,
    "total_dirty": 28672,
    "total_inactive_anon": 1687552,
    "total_inactive_file": 29974528,
    "total_mapped_file": 1675264,
    "total_pgfault": 295316278,
    "total_pgmajfault": 77,
    "total_pgpgin": 85138921,
    "total_pgpgout": 84964308,
    "total_rss": 605270016,
    "total_rss_huge": 0,
    "total_shmem": 5513216,
    "total_unevictable": 0,
    "total_writeback": 0,
    "unevictable": 0,
    "writeback": 0
  ,
  "limit": 5368709120
,

https://github.com/google/cadvisor/issues/638 上的评论断言:

总计 (memory.usage_in_bytes) = rss + 缓存

https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt 说:

usage_in_bytes:为了效率,和其他内核组件一样,内存 cgroup 使用了一些优化 避免不必要的缓存线错误共享。 usage_in_bytes 受 方法并且不显示内存(和交换)使用的“确切”值,这是一个模糊 高效访问的价值。 (当然,必要时,它是同步的。) 如果你想知道更准确的内存使用情况,你应该使用 RSS+CACHE(+SWAP) memory.stat 中的值(参见 5.2)。

https://docs.docker.com/engine/reference/commandline/stats/#parent-command 说:

注意:在 Linux 上,Docker CLI 通过从总内存使用量中减去页面缓存使用量来报告内存使用量。 API 不执行此类计算,而是提供总内存使用量和页面缓存的数量,以便客户端可以根据需要使用数据。

确实,容器中 /sys/fs/cgroup/memory/memory.stat 中的大部分内容都显示在上述 docker stats api 响应中(略有不同是因为在不同时间采集样本,抱歉) :

meme@myapp-56b947bf6d-2lcr7:/app# cat /sys/fs/cgroup/memory/memory.stat
cache 119492608
rss 607436800
rss_huge 0
shmem 5525504
mapped_file 1675264
dirty 69632
writeback 0
pgpgin 85573974
pgpgout 85396501
pgfault 296366011
pgmajfault 80
inactive_anon 1687552
active_anon 611213312
inactive_file 32800768
active_file 81166336
unevictable 0
hierarchical_memory_limit 5368709120
total_cache 119492608
total_rss 607436800
total_rss_huge 0
total_shmem 5525504
total_mapped_file 1675264
total_dirty 69632
total_writeback 0
total_pgpgin 85573974
total_pgpgout 85396501
total_pgfault 296366011
total_pgmajfault 80
total_inactive_anon 1687552
total_active_anon 611213312
total_inactive_file 32800768
total_active_file 81166336
total_unevictable 0

来自kubectl describe pod <pod>的内存信息:

Limits:
  memory:  5Gi
Requests:
  memory:   4Gi

这是pmap 在容器内所说的内容。在这个单行中,我获取所有进程 ID,在它们上运行 pmap -x,然后从 pmap 结果中提取 Kbytes 列。总结果是 256 MB(比 ps 的 RSS 少得多,我认为部分原因是因为许多进程没有从 pmap -x 返回任何输出):

ps aux | awk 'print $2' | grep -v PID | xargs sudo pmap -x | grep total | grep -v grep | awk 'print $3' | awk 's+=$1 END printf "%.0f", s'; echo
256820

ps_mem.py 在https://***.com/a/133444/6090676 中提及。它检查/proc/$pid/statm/proc/$pid/smaps。这里没有照明(再次,它似乎忽略了一些过程):

# python ps_mem.py
Private  +   Shared  =  RAM used    Program

  1.7 MiB +   1.0 MiB =   2.7 MiB   apache2
  2.0 MiB +   1.0 MiB =   3.0 MiB   bash (3)
---------------------------------
                          5.7 MiB
=================================

Incorrect reporting of container memory usage by cadvisor 上还有另一个与此类似的问题(但信息较少)。谢谢!

【问题讨论】:

$ bytes=$(ps aux | grep -v grep | grep -v 'ps aux' | grep -v bash | grep -v awk | grep -v RSS | awk 's+=$1 END printf "%.0f", s');兆字节=$(expr $bytes / 1024); printf "bytes: $bytes\nmibibytes: $megabytes\n" - 您发布的命令应该计算第一列的总和,即用户名,但 RSS 为 6 美元。您确定您计算的值正确吗? 您是对的,谢谢,已更正!我在发布问题时拼写了命令。命令输出中的数字基于第 6 列并且是正确的。 你能告诉我们kubectl describe pod <pod>吗?特别是任何可能出现的内存设置。 添加到问题的末尾! 您使用的是哪个 Kubernetes 版本?我只是试图重现这一点,但它在 1.10 中按预期工作。 【参考方案1】:

我不知道你是否已经找到答案,但让我给你一些可能有帮助的信息。

cAdvisor 提取许多与内存相关的指标。我们将专注于:

    container_memory_usage_bytes -> 获取内存使用情况。来自 memory.usage_in_bytes 文件。

    container_memory_working_set_bytes -> 在 cAdvisor 中计算。它是 usage。换句话说,usage = working_set_bytes + total_inactive_file

    container_memory_rss -> 等于来自 memory.state 文件的total_rss

现在您知道这些指标是如何收集的,您需要知道,当您使用kubectl top pods 命令时,您会得到container_memory_working_set_bytes 的值而不是usage 指标。

从你的价值观来看:

5039Mi“来自 kubectl 命令的工作集”~= 5064“来自 memory.usage 文件”- 28“来自 docker 容器统计 API 的内存部分的 total_inactive_file”

还值得一提的是,当container_memory_usage_bytes 的值达到极限时,您的 pod 不会被 oom-killed。但是如果container_memory_working_set_bytescontainer_memory_rss 达到限制,则该吊舱将被杀死。

【讨论】:

给定working_set_bytes = memory_usage_in_bytes - total_inactive_file 那么total_rss 应该已经是memory_usage_in_bytes 的一部分,无论如何,据我所知。所以working_set_bytes应该是唯一关心OOM杀的指标吗?也在这里描述:faun.pub/… container_memory_usage_bytes 达到限制时会发生什么?性能影响?还是什么都没有?【参考方案2】:

我没有看到你在这里检查的一件事是内核内存。这也在memory.usage_in_bytes 图中进行了说明,但未出现在memory.stat 中。您可以通过查看 /sys/fs/cgroup/memory/memory.kmem.usage_in_bytes 找到它。

我曾经看到我们的一个 .NET 核心应用程序发生了类似的事情,但我无法弄清楚到底发生了什么(可能是 .NET 核心中的内存泄漏,因为它是我们的应用程序无法控制的非托管内存)。

也许这对您来说是另一个面包屑。使用是否正常取决于您的应用程序,但就 cgroups 而言,我相信默认情况下内核内存使用不受限制。

【讨论】:

以上是关于内存使用差异:docker 容器内的 cgroup memory.usage_in_bytes 与 RSS的主要内容,如果未能解决你的问题,请参考以下文章

Docker Cgroup 容器资源限制

Docker容器之Cgroup资源配置!

Docker容器之Cgroup资源配置!

Docker容器之Cgroup资源配置!

理解Docker:Docker 容器使用 cgroups 限制资源使用

centos7下安装docker(10容器底层--cgroup和namespace)