容器实战高手课
李程远
eBay 总监级工程师,云平台架构师
4428 人已学习
立即订阅
登录后,你可以任选4讲全文学习
推荐试读
换一换
01 | 认识容器:容器的基本操作和实现原理
07 | Load Average:加了CPU Cgroup限制,为什么我的容器还是很慢?
11 | 容器文件系统:我在容器中读写文件怎么变慢了?
课程目录
已完结/共 31 讲
开篇词 (2讲)
开篇词 | 一个态度两个步骤,成为容器实战高手
01 | 认识容器:容器的基本操作和实现原理
容器进程 (6讲)
02 | 理解进程(1):为什么我在容器中不能kill 1号进程?
03|理解进程(2):为什么我的容器里有这么多僵尸进程?
04 | 理解进程(3):为什么我在容器中的进程被强制杀死了?
05|容器CPU(1):怎么限制容器的CPU使用?
06 | 容器CPU(2):如何正确地拿到容器CPU的开销?
07 | Load Average:加了CPU Cgroup限制,为什么我的容器还是很慢?
容器内存 (3讲)
08 | 容器内存:我的容器为什么被杀了?
09 | Page Cache:为什么我的容器内存使用量总是在临界点?
10 | Swap:容器可以使用Swap空间吗?
容器存储 (4讲)
11 | 容器文件系统:我在容器中读写文件怎么变慢了?
12 | 容器文件Quota:容器为什么把宿主机的磁盘写满了?
13 | 容器磁盘限速:我的容器里磁盘读写为什么不稳定?
14 | 容器中的内存与I/O:容器写文件的延时为什么波动很大?
容器网络 (4讲)
15 | 容器网络:我修改了/proc/sys/net下的参数,为什么在容器中不起效?
16 | 容器网络配置(1):容器网络不通了要怎么调试?
17|容器网络配置(2):容器网络延时要比宿主机上的高吗?
18 | 容器网络配置(3):容器中的网络乱序包怎么这么高?
容器安全 (2讲)
19 | 容器安全(1):我的容器真的需要privileged权限吗?
20 | 容器安全(2):在容器中,我不以root用户来运行程序可以吗?
结束语 (4讲)
结束语 | 跳出舒适区,突破思考的惰性
结课测试|这些容器技术的问题,你都掌握了么?
用户故事 | 莫名:相信坚持的力量,终会厚积薄发
加餐福利 | 课后思考题答案合集
专题加餐 (6讲)
加餐01 | 案例分析:怎么解决海量IPVS规则带来的网络延时抖动问题?
加餐02 | 理解perf:怎么用perf聚焦热点函数?
加餐03 | 理解ftrace(1):怎么应用ftrace查看长延时内核函数?
加餐04 | 理解ftrace(2):怎么理解ftrace背后的技术tracepoint和kprobe?
加餐05 | eBPF:怎么更加深入地查看内核中的函数?
加餐06 | BCC:入门eBPF的前端工具
容器实战高手课
15
15
1.0x
00:00/00:00
登录|注册
开通超级会员可免费学习本课程,还可解锁海量内容免费学特权。

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

你好,我是程远。
上一讲,我们讲了 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/1000字
划线
笔记
复制
01 | 认识容器:容器的基本操作和实现原理
07 | Load Average:加了CPU Cgroup限制,为什么我的容器还是很慢?
11 | 容器文件系统:我在容器中读写文件怎么变慢了?
13 | 容器磁盘限速:我的容器里磁盘读写为什么不稳定?
加餐03 | 理解ftrace(1):怎么应用ftrace查看长延时内核函数?
加餐05 | eBPF:怎么更加深入地查看内核中的函数?
开通超级会员免费畅看本课程
开通会员
该文章仅可免费阅读部分内容,如需阅读完整文章,请开通超级会员或单独购买本课程。
登录 后留言

精选留言(16)

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

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

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

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

    2020-12-05
    2
    7
  • 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
    5
  • 垂死挣扎的咸鱼
    请问老师:这边结合了课程内容以及评论中的一些补充想在确认一下以下几个问题:
    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
    3
  • 垂死挣扎的咸鱼
    老师,这边在请教两个问题,
    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
    2
    2
  • 上邪忘川
    看了这篇文章,对于linux内存的机制和free的使用有了很大的认识

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

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

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

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

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

    2020-12-05
    1
  • Geek_047c45
    老师你好。想请教一下rss里面代码段部分是不是应该属于pagecache里面,因为我看前面统计容器内存时先做了是否是匿名页的判断。在我的认知里pagecache里的页都是映射页(swapcache不知道算不算),rss里的页包含映射页和匿名页
    2021-10-11
  • 左氧佛沙星人
    老师好,一般active/inactive_anon 是指什么呢?看了很多资料都说的很模糊
    2021-09-30
  • 仲玄
    老师, page cache 如果都被回收了, 会不会没办法使用page cache 导致磁盘很慢?

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

    2021-08-11
  • Q~Q
    请问老师: 容器内file-backed过大导致容器oom这个案例有遇到过吗 我现在遇到过一个现象 容器内由于读取的是宿主机的proc/meminfo 导致cache没办法回收

    作者回复: /proc/meminfo里只有一些统计信息,内容很少,不会占用大量的内存。

    2021-07-30
  • BertGeek
    docker容器内存资源限制有了新的认知

    作者回复: 很开心对你有帮助!

    2021-07-01
  • 13549804879
    老师,我看过一些liunx的书,看了很容易就忘记了。如何能做到与实践想结合,或者用代码演示kernel的代码。这样可能会容易理解。请问有什么相关的案例书籍推荐。

    作者回复: 我这里没有案例相关书籍。
    不过学习kernel还是需要长期的坚持。

    2021-05-13
  • alpha
    老师,你好 最近我们在迁移docker时发现当应用第一次去使用到swap的内存时,应用会有几秒的响应延迟?这个问题如何解决?

    作者回复: @alpha,
    你的意思是把程序迁移到容器中后,程序的内存被交换到swap空间,这时候应用会有延时?
    你这里说的“当应用第一次去使用到swap的内存时”是怎么判断的?

    2021-04-11
    2
收起评论
16
返回
顶部