I
Editorial
容器或 systemd 单元突然被杀,日志里只有 Memory cgroup out of memory——未必是真泄漏,也可能是 limit、swap、pressure 与 OOM 杀手策略没配对。本帖按 cgroup v2 场景整理「先看压力信号 → 再分清 limit/高水位/匿名页 → 最后做可复现验收」,命令以主流发行版为准。
一、先看哪些信号
1. memory.current / memory.peak:是否贴着 memory.max;只有 peak 冲顶而长期很低,多半是尖峰而非稳态泄漏。
2. memory.pressure(PSI):some/full 是否长时间升高;full 高说明已经在停工等回收。
3. 内核日志:oom-kill 的 victim、total-vm、anon-rss、file-rss;看清杀的是业务进程还是同组里的 sidecar。
4. 宿主对比:整机 MemAvailable、是否启用 zswap/swap;组内禁止 swap 时,尖峰更容易直接 OOM。
二、定位顺序
1. 确认层级:统一层级(unified)下 memory 控制器是否挂到目标 cgroup;混用 v1 命名会让你改错文件。
2. 分清 memory.max 与 memory.high:high 是软压制(throttle/reclaim),max 是硬顶;只调 high 却指望「永不 OOM」会误判。
3. 看回收对象:file cache 可回收时 PSI 升高不一定该加 limit;匿名页(堆、JVM、Go)涨才更像真需求或泄漏。
4. 容器运行时:kube 的 requests/limits、Burstable 与 OOM 分数;limits 过紧时,同 Pod 里日志侧车先被杀也很常见。
5. 应用侧尖峰:启动预热、大查询、缓冲池一次性抬升;用 peak 与业务发布时间对齐,避免把发布尖峰当泄漏。
三、缓解与配置习惯
1. 给可回收缓存留余量:纯计算型可贴近实际工作集;含页面缓存的服务避免把 max 设成「刚好等于 RSS」。
2. 明确 swap 策略:要么组内允许有限 swap 吸收尖峰,要么彻底禁用并按 peak 定容;半开半关最难排。
3. 指标进告警:memory.pressure full、oom_kill 计数、container_memory_working_set 与 limit 比,分别设阈。
4. 版本与内核:老内核 PSI/ OOM 行为有差异;升级后用同一压测用例回归。
四、验收与复现
1. 用可控分配器(或业务压测)打到 high/max,确认是 throttle 还是 kill,以及受害者是否符合预期优先级。
2. 发布与大查询各跑一轮,记录 peak 与 PSI,写入容量基线。
3. 变更记录:limit/high、swap、qos class、内核版本;否则下次误杀只能凭感觉。
五、常见误区
- 一见 OOM 就无脑加 limit,掩盖泄漏,拖到宿主一起抖。
- 只盯 docker stats 的「使用量」,不看 pressure 与 anon/file 结构。
- 把宿主 free 当容器可用内存,忽略 cgroup 硬顶。
欢迎分享你们在 K8s/裸机 systemd 上对 memory.high 与 OOM 分数的实践阈值。
一、先看哪些信号
1. memory.current / memory.peak:是否贴着 memory.max;只有 peak 冲顶而长期很低,多半是尖峰而非稳态泄漏。
2. memory.pressure(PSI):some/full 是否长时间升高;full 高说明已经在停工等回收。
3. 内核日志:oom-kill 的 victim、total-vm、anon-rss、file-rss;看清杀的是业务进程还是同组里的 sidecar。
4. 宿主对比:整机 MemAvailable、是否启用 zswap/swap;组内禁止 swap 时,尖峰更容易直接 OOM。
二、定位顺序
1. 确认层级:统一层级(unified)下 memory 控制器是否挂到目标 cgroup;混用 v1 命名会让你改错文件。
2. 分清 memory.max 与 memory.high:high 是软压制(throttle/reclaim),max 是硬顶;只调 high 却指望「永不 OOM」会误判。
3. 看回收对象:file cache 可回收时 PSI 升高不一定该加 limit;匿名页(堆、JVM、Go)涨才更像真需求或泄漏。
4. 容器运行时:kube 的 requests/limits、Burstable 与 OOM 分数;limits 过紧时,同 Pod 里日志侧车先被杀也很常见。
5. 应用侧尖峰:启动预热、大查询、缓冲池一次性抬升;用 peak 与业务发布时间对齐,避免把发布尖峰当泄漏。
三、缓解与配置习惯
1. 给可回收缓存留余量:纯计算型可贴近实际工作集;含页面缓存的服务避免把 max 设成「刚好等于 RSS」。
2. 明确 swap 策略:要么组内允许有限 swap 吸收尖峰,要么彻底禁用并按 peak 定容;半开半关最难排。
3. 指标进告警:memory.pressure full、oom_kill 计数、container_memory_working_set 与 limit 比,分别设阈。
4. 版本与内核:老内核 PSI/ OOM 行为有差异;升级后用同一压测用例回归。
四、验收与复现
1. 用可控分配器(或业务压测)打到 high/max,确认是 throttle 还是 kill,以及受害者是否符合预期优先级。
2. 发布与大查询各跑一轮,记录 peak 与 PSI,写入容量基线。
3. 变更记录:limit/high、swap、qos class、内核版本;否则下次误杀只能凭感觉。
五、常见误区
- 一见 OOM 就无脑加 limit,掩盖泄漏,拖到宿主一起抖。
- 只盯 docker stats 的「使用量」,不看 pressure 与 anon/file 结构。
- 把宿主 free 当容器可用内存,忽略 cgroup 硬顶。
欢迎分享你们在 K8s/裸机 systemd 上对 memory.high 与 OOM 分数的实践阈值。