内存使用差异:cgroup 内存.usage_in_bytes 与 Docker 容器内的 RSS。

45
“Kubernetes”(v1.10.2)显示我的Pod(包含一个容器)正在使用约5GB的内存。但是容器内部的RSS显示更多,大约是681MiB。有人可以解释一下如何从这些数据中得出5GB,或者用另一个命令来补足差距吗?kubectl top pods显示5GB。
% kubectl top pods -l app=myapp
NAME                             CPU(cores)   MEMORY(bytes)
myapp-56b947bf6d-2lcr7           39m          5039Mi

Cadvisor报告了一个类似的数字(可能来自稍微不同的时间,请忽略小的差异):

container_memory_usage_bytes{pod_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上的一条评论声称:

  

Total(memory.usage_in_bytes)= rss + cache

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

  

usage_in_bytes:为了提高效率,与其他内核组件一样,内存cgroup使用一些优化来避免不必要的缓存行错误共享。 usage_in_bytes受方法影响,并且不显示内存(和交换)使用的“确切”值,它是用于有效访问的模糊值。 (当然,在必要时,它是同步的。)如果您想了解更精确的内存使用情况,则应在memory.stat中使用RSS + CACHE(+ SWAP)值(请参见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兆字节(远小于 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.pyhttps://dev59.com/KnVC5IYBdhLWcg3w-WSs#133444 中被提到。它检查 /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
=================================

这里还有一个类似的问题(但信息较少)在https://dev59.com/k6Xja4cB1Zd3GeqPXdq3。 谢谢!


$ 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}'); megabytes = $(expr $ bytes / 1024); printf "bytes:$ bytes \ n mibibytes:$ megabytes \ n" - 您发布的命令应计算第一列(即用户名)的总和,但RSS是$ 6。您确定已计算正确的值吗? - VAS
你说得对,谢谢,已经更正了!我在发布问题时输错了命令。命令输出中的数字是基于第6列的,是正确的。 - burnettk
1
你能展示一下 kubectl describe pod <pod> 吗?特别是任何可能出现的内存设置。 - Robert
请提供需要翻译的英文文本。 - burnettk
1
你使用的Kubernetes版本是哪个?我刚试图复现这个问题,但在我的1.10版本上正常工作。 - Michael Hausenblas
显示剩余4条评论
2个回答

12

我注意到你这里没有检查内核内存。这也被计入了memory.usage_in_bytes的数字中,但是在memory.stat中不会显示。你可以通过查看/sys/fs/cgroup/memory/memory.kmem.usage_in_bytes来找到它。

我曾经发现我们的一个.NET Core应用程序也出现了类似的情况,但我无法确定具体发生了什么(也许是由于.NET Core中存在内存泄漏,因为我们的应用程序无法控制非托管内存)。

也许这是另一条线索。这取决于您的应用程序是否正常使用,但就cgroups而言,我认为默认情况下内核内存使用是不受限制的。


要了解更多信息,我建议阅读这篇很棒的文章:https://medium.com/@bobzsj87/demist-the-memory-ghost-d6b7cf45dd2a - undefined

11

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

  • cAdvisor提取了许多与内存相关的指标,我们将重点关注以下几点:

    1. container_memory_usage_bytes = /sys/fs/cgroup/memory/memory.usage_in_bytes文件中的值。(内存使用量)

    2. container_memory_working_set_bytes = container_memory_usage_bytes - total_inactive_file (来自/sys/fs/cgroup/memory/memory.stat),这在cAdvisor中进行计算,且 <= container_memory_usage_bytes

    3. container_memory_rss = /sys/fs/cgroup/memory/memory.stat中的total_rss

  • 现在你知道了如何收集这些指标,你需要知道当你使用 kubectl top pods 命令时,你得到的是container_memory_working_set_bytes而不是container_memory_usage_bytes

    所以从你的数据来看:

    5039Mi "来自kubectl命令的工作集" ~= 5064 "来自memory.usage文件" - 28 "来自docker容器统计API的内存部分的总非活动文件"

  • 值得一提的是,当container_memory_usage_bytes的值达到限制时,您的Pod不会被oom-kill。但是,如果container_memory_working_set_bytescontainer_memory_rss达到限制,该Pod将被终止。


  • 假设 working_set_bytes = memory_usage_in_bytes - total_inactive_file,那么据我理解,total_rss 应该已经作为 memory_usage_in_bytes 的一部分了。所以在关注 OOM kills 时,working_set_bytes 应该是唯一需要关心的度量标准,详见 https://faun.pub/how-much-is-too-much-the-linux-oomkiller-and-used-memory-d32186f29c9d - Daniel Föhr
    container_memory_usage_bytes 达到限制时会发生什么?会有性能影响吗?还是没有影响? - Salmaan P
    结论“container_memory_working_set_bytes或container_memory_rss达到限制时,Pod将会被终止。”是不正确的:container_memory_working_set_bytes包括total_active_file,当它达到限制时,total_active_file将会被回收,而Pod将不受影响。请参阅https://github.com/kubernetes/kubernetes/issues/43916和https://github.com/kubernetes/kubernetes/issues/104533。 - Kelvin Hu

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接