容器实战高手课
李程远
eBay 总监级工程师,云平台架构师
24647 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 31 讲
容器实战高手课
15
15
1.0x
00:00/00:00
登录|注册

09 | Page Cache:为什么我的容器内存使用量总是在临界点?

提高磁盘文件读写性能
存放磁盘文件读写页面的内存
包括代码段内存、堆内存、栈内存、共享库内存
进程实际申请到的物理页面内存大小
容器内存使用状况应更多考虑RSS内存
内存紧张时,Page Cache内存会被释放
容器内存使用量包括RSS和Page Cache
RSS值对容器内存使用量的判断更为准确
验证Memory Cgroup内存类型的实际开销
内存回收机制释放Page Cache内存
Memory Cgroup统计RSS和Page Cache内存
Page Cache
RSS (Resident Set Size)
写磁盘文件的程序对Memory Cgroup内存的影响
重点总结
解决问题
RSS & Page Cache in Memory Cgroup
Linux系统内存类型
内存使用量与上限值相差不大
容器内存接近上限值,仍能申请内存
思考题
知识详解
问题再现
为什么容器内存使用量总是在临界点

该思维导图由 AI 生成,仅供参考

你好,我是程远。
上一讲,我们讲了 Memory Cgroup 是如何控制一个容器的内存的。我们已经知道了,如果容器使用的物理内存超过了 Memory Cgroup 里的 memory.limit_in_bytes 值,那么容器中的进程会被 OOM Killer 杀死。
不过在一些容器的使用场景中,比如容器里的应用有很多文件读写,你会发现整个容器的内存使用量已经很接近 Memory Cgroup 的上限值了,但是在容器中我们接着再申请内存,还是可以申请出来,并且没有发生 OOM。
这是怎么回事呢?今天这一讲我就来聊聊这个问题。

问题再现

我们可以用这里的代码做个容器镜像,然后用下面的这个脚本启动容器,并且设置容器 Memory Cgroup 里的内存上限值是 100MB(104857600bytes)。
#!/bin/bash
docker stop page_cache;docker rm page_cache
if [ ! -f ./test.file ]
then
dd if=/dev/zero of=./test.file bs=4096 count=30000
echo "Please run start_container.sh again "
exit 0
fi
echo 3 > /proc/sys/vm/drop_caches
sleep 10
docker run -d --init --name page_cache -v $(pwd):/mnt registry/page_cache_test:v1
CONTAINER_ID=$(sudo docker ps --format "{{.ID}}\t{{.Names}}" | grep -i page_cache | awk '{print $1}')
echo $CONTAINER_ID
CGROUP_CONTAINER_PATH=$(find /sys/fs/cgroup/memory/ -name "*$CONTAINER_ID*")
echo 104857600 > $CGROUP_CONTAINER_PATH/memory.limit_in_bytes
cat $CGROUP_CONTAINER_PATH/memory.limit_in_bytes
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了容器内存管理中的关键问题:容器内存使用量总是在临界点的现象。通过具体案例和技术原理的阐述,文章首先展示了容器内存接近上限值时仍能继续申请内存的现象,并提出了这一现象的疑问。随后,详细解释了Linux系统中的内存类型,包括RSS和Page Cache,并阐述了它们对Memory Cgroup的影响。作者指出,Memory Cgroup只统计了RSS和Page Cache这两部分内存,而当控制组内的进程需要申请新的物理内存时,会调用Linux的内存回收机制来释放Page Cache内存,以保证整个控制组内的总物理内存开销不会超过上限值。这一解释为容器内存使用量总是在临界点的现象提供了合理的解释。 总的来说,本文通过具体案例和技术原理阐述了容器内存使用量在临界点时的表现和原因,为读者提供了深入了解容器内存管理的知识和解决问题的思路。文章重点强调了在判断容器的内存使用状况时,需要忽略Page Cache这部分内存使用量,而更多地考虑容器中RSS的内存使用量。这一观点对于容器内存管理的实际应用具有重要指导意义。 通过本文的阐述,读者可以更好地理解容器内存管理中的关键概念和技术原理,为他们在实际应用中解决类似问题提供了有益的思路和方法。同时,文章提出了思考题,鼓励读者深入思考并与他人交流探讨,促进技术交流和共同学习。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《容器实战高手课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(24)

  • 最新
  • 精选
  • 莫名
    Momory Cgroup 应该包括了对内核内存的限制,老师给出的例子情况比较简单,基本没有使用 slab,可以试下在容器中打开海量小文件,内核内存 inode、dentry 等会被计算在内。 内存使用量计算公式(memory.kmem.usage_in_bytes 表示该 memcg 内核内存使用量): memory.usage_in_bytes = memory.stat[rss] + memory.stat[cache] + memory.kmem.usage_in_bytes 另外,Memory Cgroup OOM 不是真正依据内存使用量 memory.usage_in_bytes,而是依据 working set(使用量减去非活跃 file-backed 内存),working set 计算公式: working_set = memory.usage_in_bytes - total_inactive_file

    作者回复: @莫名, 很赞!每次你都可以更深入的挖掘知识点!

    2020-12-07
    6
    74
  • 蒋悦
    您好,问一个操作系统相关的问题。根据我的理解,操作系统为了性能会在刷盘前将内容放在page cache中(如果可以申请的话),后续合适的时间刷盘。如果是这样的话,在一定条件下,可能还没刷盘,这个内存就需要释放给rss使用。这时必然就会先刷盘。这样会导致 系统 malloc 的停顿,对吗?如果是这样的话,另外一个问题就是 linux 是如何保证 磁盘的数据的 crash safe 的呢?

    作者回复: 是的,在系统申请物理内存的时候,如果不够,会因为释放page cache而增加延时。 对于在page cache中的dirty page, 有kernel thread会根据dirty_* 相关的参数在在后台不断的写入磁盘。不过如果发生断电,那么在内存中还没有写入的dirty page还是丢失的。

    2020-12-04
    12
  • Alery
    首先,很感谢老师,从您这几节关于容器的文章学到了很多知识点,感觉自己以前了解的容器都是些皮毛,在学习的过程中发现容器的很多的问题都需要深入了解操作系统或者linux内核相关的知识,这块知识是我比较缺失的,除了继续打卡老师的文章,空闲时间还想系统的学习一下操作系统及内核相关的知识,老师可以推荐几本讲操作系统或者linux内核相关的书籍吗?

    作者回复: @Alery, 可以看一下这些书, “Advanced Programming in the UNIX Environment ” “Linux Kernel Development ” “Understanding the Linux Kernel”

    2020-12-05
    3
    9
  • Geek3340
    page_cache是不是会被很多进程共享呢,比如同一个文件需要被多个进程读写,这样的话,page_cache会不会无法被释放呢? 另外,老师能不能讲解下,这里面的page_cache和free中的cache、buffer、shared还有buffer cache的区别呢?

    作者回复: 即使page cache对应的文件被多个进程打开,在需要memory的时候还是可以释放page cache的。进程打开的只是文件,page cache只是cache。 free里的cache/buffer就是page cache, 早期Linux文件相关的cache内存分buffer cache和page cache, 现在统一成page cache了。 shared内存一般是tmpfs 内存文件系统的用到的内存。

    2020-12-04
    2
    6
  • 垂死挣扎的咸鱼
    请问老师:这边结合了课程内容以及评论中的一些补充想在确认一下以下几个问题: 1 Memory Cgroup OOM 的依据是working set吗?还是说rss,working set都会进行判断 2 这边看到有评论的大佬给了对于memory.usage_in_bytes 以及working_set ,但是对这两个间的关系有一些疑惑,想请问一下老师是否可以理解为working_set = memory.stat[rss] + memory.kmem.usage_in_bytes+常用的page cache 这样?

    作者回复: @Geek_295fee > 1 OOM 判断还是根据 新申请的内存+ memory.usage_in_bytes - reclaim memory > memory.limit_in_bytes 来判断的。 > 2 working_set应该是cAdvsior里的一个概念,可以看一下下面的这段代码。它的定义是 memory.usage_in_bytes - inactive_file memory。不过在memory reclaim的时候,可以reclaim的memory是大于 inactive_file memory的。 https://github.com/google/cadvisor/blob/master/container/libcontainer/handler.go#L870

    2021-02-04
    5
  • 垂死挣扎的咸鱼
    老师,这边在请教两个问题, 1 cgroup底下的memory.stat文件中inactive_file 是否在oom时能回收,因为这边看到代码里描述workset = memory.usage-inactive_file这个值获得的,而这边看到在评论区里有大佬提到Memory Cgroup OOM会以working set为标准 2 在查看某个容器的时候发现container_memory_working_set_bytes远小于container_memory_rss指标,原因是因为inactive_file的值非常大,因此这个时候内存监控的时候用container_memory_working_set_bytes似乎看不出来是否马上就要oom这样,因此比较困惑如果想要监控内存的使用率判断oom该使用哪个指标? 下面是查看cgroup的情况: cat /sys/fs/cgroup/memory/memory.stat .... rss 2666110976 ... inactive_anon 0 active_anon 172163072 inactive_file 2489147392 active_file 7667712 .... total_cache 2596864 total_rss 2666110976 total_rss_huge 276824064

    作者回复: @垂死挣扎的咸鱼 这个问题很有趣,inactive_file 一般是指page cache, 应该被计入cache部分, 是可以被reclaim的, 但是在你的这个例子是,这部分值被计入了rss。你可以简单说一下,你容器中的应用的工作特点吗?

    2021-04-13
    3
    2
  • 笃定
    老师,如果新程序申请的内存大小是大于之前进程的page cache内存大小的;是不是就会发生oom?

    作者回复: 这个还要看之前page cache总共使用了多少。 如果新进程最后实际使用到的内存, 比如RSS, 和之前进程的RSS相加大于容器的内存限制,那么就会发生OOM.

    2021-03-30
    2
  • 上邪忘川
    看了这篇文章,对于linux内存的机制和free的使用有了很大的认识

    编辑回复: 谢谢鼓励,咱们一起学习进步~

    2020-12-06
    2
  • 流浪地球
    请问文中提到rss包括共享内存的大小,那pss呢,pss和rss的区别不是 是否包括共享内存的大小码?

    作者回复: pss对共享内存的计算做了一下处理,比如100个页面是两个进程共享的,那么每个进程只记录50个页面在自己进程的pss里。

    2020-12-05
    2
  • 仲玄
    老师, page cache 如果都被回收了, 会不会没办法使用page cache 导致磁盘很慢?

    作者回复: 如果在内存很紧张的情况下,的确会出现反复reclaim cache的情况, 对磁盘读写肯定有影响。

    2021-08-11
收起评论
显示
设置
留言
24
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部