前言

本文主要会介绍笔者在学习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个核心参数为:

  1. memory.limit_in_bytes 即限制Control Group中所有进程可使用的最大内存值。

  2. memory.oom_control 当Control Group中进程使用的内存大于等于最大内存上限(即memory.limit_in_bytes)时,如果该参数值为1,则表示系统不会对该情况触发OOM Killer操作。该参数默认为0,即默认会触发OOM Killer操作。

  3. memory.soft_limit_bytes 即软限制,只有比强制限制设置的值小的时候才有意义。当整体内存紧张的情况下,进程获取的内存就被限制在软限制额度之内,以保证不会有太多进程因内存挨饿。

Tips: 这里需要注意的是,加入了内存的资源限制并不代表没有资源竞争。

  1. 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 限制,单位为字节