我正在尝试了解内存请求和限制如何与 cgroup v2 配合使用。在 Kubernetes 清单中,我们可以配置内存请求和内存限制。然后使用这些值来配置 cgroup 接口:
- memory.min 设置为内存请求
- memory.max 设置为内存限制
- memory.high 设置为内存限制 * 0.8,除非内存请求 == 限制,在这种情况下 memory.high 保持未设置状态
- memory.low 始终未设置
memory.max 的含义非常明显:当 cgroup 中的进程尝试分配页面,这会使内存使用量超过 memory.max,并且无法从 cgroup 中回收足够的页面来满足 memory.max 内的请求时,则会调用 OOM killer 来终止 cgroup 中的进程。memory.high 更难理解:内核文档说,当达到高水位时,cgroup 会面临“高回收压力”,但这究竟意味着什么?
后来又说:
当达到上限时,它会通过强制直接回收来限制分配,以消除多余的部分,但它永远不会调用 OOM 杀手。
我是否正确地假设这意味着当 cgroup 尝试分配超出 memory.high 水位线的页面时,它将同步查看 lruvecs 并尝试从列表末尾回收尽可能多的页面,直到它回到高水位线以下?或者“回收压力”是异步发生的(通过 kswapd)?
问题 2:在 Kubernetes 上使用 memory.high 有什么意义?据我所知,Kubernetes 节点通常在没有交换空间的情况下运行。唯一可回收的页面是匿名页面(如果有足够的交换空间)和页面缓存。由于没有交换空间,因此只剩下页面缓存。问题是,在达到 memory.max 时也会回收页面缓存,如果无法回收任何内容,则在最后调用 OOM 终止程序。那么 memory.high 基本上是无用的:
只要使用页面缓存,它总是可以被回收,memory.max 也会这样做。使用 memory.high,我们只是在必要之前限制应用程序。不妨首先将 memory.max 设置得更低一些。
如果没有使用显著的页面缓存(目前运行 Kubernetes 的大多数应用程序可能都是这种情况),那么就无法回收任何内容,因此没有节流(没有分页未使用的匿名内存,压力失速信息中没有可见的抖动来警告我们),我们将毫无察觉地遇到 memory.max。使用 memory.high 没有任何效果。