前言
本文主要会介绍笔者在学习Linux Cgroups Memory Subsystem时所总结的知识点,其中会涉及到使用方式、核心配置参数
等方面的相关内容。
笔者也会将自己的理解在文中进行阐述,这也算是在和大家交流心得的一个过程。若文中有错误的理解和概念,请大家及时纠正;吸纳大家的建议,对于我来说也是很重要的学习过程之一。
(目录)
1.Linux内存类型
对于内存这类计算资源,Linux Cgroups Memory Subsystem会对不同类型的内存进行统计,并依据多种内存类型的数据来实现内存资源限制的相关逻辑。因此了解Linux内存类型的相关知识有助于更好的配置和理解Linux Cgroups Memory Subsystem对内存资源的限制方式。
Linux的各个模块都需要内存,比如内核需要分配内存给页表、内核栈、还有 slab(即内核各种数据结构的 Cache Pool)、用户态进程里的堆内存和栈的内存、共享库的内存和文件读写的 Page Cache。
1.2 RSS
RSS(Resident Set Size)即为进程真正申请到物理页面的内存大小
。
对于进程来说,RSS 内存包含了进程的代码段内存,栈内存,堆内存,共享库的内存, 这些内存是进程运行所必须的。具体的每一部分的 RSS 内存的大小,可以查看 /proc/[pid]/smaps 文件。
1.2 Page Cache
每个进程除了各自独立分配到的 RSS 内存外,如果进程对磁盘上的文件做了读写操作,Linux 还会分配内存把磁盘上读写到的页面存放在内存中,这部分的内存就是 Page Cache。
Page Cache 的主要作用是提高磁盘文件的读写性能
。因为系统调用 read() 和 write() 的缺省行为都会把读过或者写过的页面存放在 Page Cache 里。
Tips: 由于Page Cache 的内存页面只是起到 Cache 作用,因此Linux的内存回收机制执行时,其往往会被优先释放掉。
1.3 Anonymous memory
在 RSS 里的内存大部分都是没有对应磁盘文件的内存
(例如用 malloc() 申请得到的内存),这种内存也被称为匿名内存(Anonymous memory)
。
此时如果Swap空间可以使用,则写入 Swap 空间的就是这些匿名内存。
2.Linux Cgroups Memory Subsystem
Linux Cgroups Memory Subsystem的作用是对一组进程的Memory使用做限制
。
2.1 实现方式
Linux Cgroups Memory Subsystem的虚拟文件系统的挂载点一般在"/sys/fs/cgroup/memory"这个目录下。
Tips: 实现原理可以阅读笔者另一遍介绍Linux Cgroups原理的文章
其中,每一个子目录代表一个Control Group。Control Group之间也同样是树状的层级结构;每一个Control Group中会包含多个进程。子Control Group的配置会受到父Control Group配置的限制
。即使子Control Group配置超过Control Group的配置,实际生效配置不会超过父Control Group,即父Control Group的配置为上限。
注意: 这里基于Linux Cgroups V1版本来进行讲解的。
2.2 核心参数
Linux Cgroups Memory Subsystem中的4个核心参数为:
-
memory.limit_in_bytes 即限制Control Group中所有进程可使用的最大内存值。
-
memory.oom_control 当Control Group中进程使用的内存大于等于最大内存上限(即memory.limit_in_bytes)时,如果该参数值为1,则表示系统不会对该情况触发OOM Killer操作。该参数默认为0,即默认会触发OOM Killer操作。
-
memory.soft_limit_bytes
即软限制,只有比强制限制设置的值小的时候才有意义
。当整体内存紧张的情况下,进程获取的内存就被限制在软限制额度之内,以保证不会有太多进程因内存挨饿。
Tips: 这里需要注意的是,加入了内存的资源限制并不代表没有资源竞争。
- memory.usage_in_bytes
即
当前Control Group中所有进程实际使用的内存总和
。
2.3 对于OOM的管控
memory.oom_control如果更改为1,则表示即使超过了控制组规定的最大内容限额也不会触发Linux的OOM操作。
注意:
这样的设置是很危险的
。有可能会影响到host本身的内存管理。
memory.usage_in_bytes与memory.limit_in_bytes的比值是能够体现出当前Control Group的OOM风险。比值越大,说明被触发OOM的风险越大
。
实际上: memory.usage_in_bytes = RSS + Page Cache 其中,RSS为当前Control Group中所有进程的RSS总和;而Page Cache 为当前Control Group里的所有进程读写磁盘文件产生的缓存的总和。
注意不能随意设置memory.limit_in_bytes
。如果memory.limit_in_bytes设置得过小,而进程又有很大量的 I/O操作;此时再申请新的 Page Cache 内存的时候,就会不断释放老的内存页面,而这些操作就会带来额外的系统开销。
2.4 对于SWAP的管控
Linux Cgroups Memory Subsystem可以控制对于SWAP分区的使用。 memory.swappiness 可以控制一个Control Group下面匿名内存和 page cache 的回收。在一个Control Group里,如果设置了 memory.swappiness 参数,它就会覆盖全局的 swappiness,让全局的 swappiness 在这个控制组里不起作用。
注意: 当 memory.swappiness = 0 的时候,对匿名页的回收是始终禁止的,也就是始终都不会使用 SWAP 空间。这一点与Linux系统内存管理中的swappiness=0是不同的。
2.5 内存使用统计
Linux Cgroups Memory Subsystem提供了很多对于内存使用情况的只读参数。这些只读参数通常可以用来监控进程组的内容使用量。
参数名称 | 参数说明 |
---|---|
memory.max_usage_bytes | 报告该 cgroup 中进程使用的最大内存用量 |
memory.failcnt | 报告内存达到在 memory.limit_in_bytes设定的限制值的次数 |
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 | 包含Linux Cgroups Memory Subsystem的层级的内存限制,单位为字节 |
hierarchical_memsw_limit | 包含Linux Cgroups Memory Subsystem的层级的内存加 swap 限制,单位为字节 |