设置 `--memory.high` 与 `--memory.max` 的实际效果区别

解读

国内 Docker 面试常把 cgroup v2 的内存子系统细节当成“过滤器”,用来区分“只会用 docker run”与“真正懂内核资源隔离”的候选人。
--memory.max 对应旧版 --memory,是硬上限,容器一旦触碰即触发 OOM Kill;--memory.high 是 cgroup v2 引入的软上限,内核会尽力回收内存、限速分配,但不杀进程。
面试官想听的是:你能否在生产环境利用这对参数做分级 QoS,既保护高优业务,又提升节点整体利用率,而不是背定义。

知识点

  1. cgroup v1 vs v2:Docker 20.10+ 在 Linux 5.8+ 可启用 v2,--memory.high 仅 v2 生效。
  2. memory.max:绝对阈值,达到后 cgroup 内进程立即被选杀,OOM Kill 不可捕获、不可恢复
  3. memory.high:回收阶段阈值,内核先尝试页面回收、匿名页换出、压缩缓存,若仍不足才允许突破;突破后无杀进程风险,但会阻塞新内存分配请求,表现为 RT 升高、IOWait 增加。
  4. Docker CLI 映射
    --memory 始终映射到 memory.max;
    --memory-high 需显式写,且要求宿主机已挂载 cgroup v2,否则报错“unknown flag”。
  5. 节点视角:设置 memory.high ≤ memory.max 可形成两级水位,实现“节点内存超卖+单容器保护”,是云厂商超卖比模型的核心手段。
  6. 监控差异:metrics 中 memory.high 突破仅记 memory.high_events,不会记 container_oom_events,容易被漏警。

答案

--memory.max 是容器内存的硬顶,触碰即 OOM Kill,等同于传统 --memory--memory.high软限制,内核会先通过回收机制压制用量,允许短时突破,不杀进程,但会阻塞新分配。
在生产里,我把高优业务设 memory.high=4G、memory.max=6G,低优业务直接 memory.max=4G,节点总内存 8G 却能跑下 10G 需求;高优在 4–6G 区间仅性能抖动,低优一旦到 4G 立即被杀,实现分级 QoS 与超卖兼得
前提是宿主机必须 cgroup v2,否则 Docker 不认 --memory-high 参数。”

拓展思考

  1. 混部场景:与 kubelet 的 QoS 类(Burstable/Guaranteed)结合时,把 Guaranteed Pod 的 memory.high 设成 request,max 设成 limit,可让节点在内存紧张时优先回收 Burstable,保证高优延迟敏感业务。
  2. 内存回收限速:cgroup v2 还暴露 memory.high.wmark_ratio,可调回收激进程度;在电商大促中我曾把 ratio 降到 5%,避免瞬时回收导致 P99 抖动。
  3. Serverless 安全:若平台允许用户自定义 --memory-high,需校验 high ≤ max,否则用户可构造“高频突破 high 却不被杀”的旁路攻击,耗尽节点内存引发系统级 OOM。
  4. 与 swap 联动:当 --memory-swap 未禁用且开启 swap account,memory.high 回收会优先换出匿名页,若宿主机 swap 放在低速云盘,可能把内存问题转化为IO 雪崩;此时应关闭 swap 或把 swap 放在本地 NVMe,并配套 memory.high 告警。