4. 内存故障注入:模拟内存泄漏与 OOM 实验

内存问题,说白了就是系统的「隐形杀手」。

我见过太多线上事故了——服务跑着跑着突然挂掉,监控图上内存曲线像坐过山车一样陡升,然后「啪」地断崖式下跌。事后一查,不是内存泄漏就是 OOM。你想想看,这种问题在测试环境里如果不主动去「捅」它,到了生产环境才暴露,那代价可就大了。

这一章,我们就来聊聊怎么用 ChaosBlade 主动制造内存故障,把那些隐藏的坑提前挖出来。

4.1 内存泄漏 vs. 内存占用:先分清概念

很多人把内存泄漏和内存占用搞混。我简单解释一下:

  • 内存泄漏:程序申请了内存,用完不释放。一次两次没事,但日积月累,可用内存越来越少。
  • 内存占用:程序一次性吃了大量内存,比如加载一个大文件、创建海量对象,瞬间把内存撑爆。

ChaosBlade 注入的其实是「内存占用」故障——它直接往系统里塞指定大小的内存块,模拟高内存压力。但我们可以用这个手段,来间接验证系统对内存泄漏场景的防护能力。

场景 本质 ChaosBlade 模拟方式 典型表现
内存泄漏 内存只申请不释放 持续注入内存,模拟累积效果 内存缓慢增长,GC 频繁
内存占用过高 一次性申请大量内存 一次性注入指定大小内存 内存瞬间飙升,触发 OOM
OOM 内存耗尽,进程被 Kill 注入超过可用内存的量 进程消失,日志出现 OutOfMemoryError

4.2 使用 ChaosBlade 注入内存占用故障

ChaosBlade 的 blade create mem 命令,就是我们的「内存炸弹」。我个人习惯先在小范围试,再逐步加量。

4.2.1 基础命令结构

blade create mem --mem-percent 80 --mode ram --vm-bytes 512M

参数说明:

  • --mem-percent:占用内存百分比(0-100)
  • --mode:模式,ram 表示直接占用物理内存
  • --vm-bytes:每次申请的内存块大小
  • --timeout:故障持续时间,单位秒
我的习惯:先设一个较短的 timeout(比如 30 秒),看看系统反应。别一上来就搞 5 分钟,万一真把机器搞挂了,恢复起来也麻烦。

4.2.2 实战:模拟 80% 内存占用

假设你的机器有 4GB 内存,我们来模拟占用 80%:

# 注入故障:占用 80% 内存,持续 60 秒
blade create mem --mem-percent 80 --mode ram --timeout 60

# 命令返回一个 uid,比如 abc123
# 用这个 uid 可以随时撤销故障
blade destroy abc123

执行后,用 top 或 free -h 观察内存变化。你会发现可用内存瞬间从 3.8G 掉到 800M 左右。

注意:如果系统开启了 Swap,ChaosBlade 默认会优先使用物理内存。但建议在实验前关闭 Swap,否则故障效果可能被 Swap 稀释,达不到真实压力。

4.3 OOM 实验:把系统逼到极限

OOM(Out Of Memory)实验,就是故意让内存耗尽,看系统怎么死、怎么恢复。我曾经在一个 Java 服务上做过这个实验,结果发现应用虽然挂了,但监控告警居然没触发——因为告警阈值设得太高了。嗯,这就是实验的价值。

4.3.1 触发 OOM 的两种方式

方式 命令示例 适用场景
按百分比注入 blade create mem --mem-percent 100 快速验证 OOM Killer 机制
按固定大小注入 blade create mem --vm-bytes 4096M 精确控制内存压力,适合压测

4.3.2 完整 OOM 实验流程

我一般按这个步骤来:

  1. 记录基线:用 free -m 和 dmesg | tail 记录实验前的内存状态。
  2. 注入故障:执行 blade create mem --mem-percent 95 --mode ram --timeout 120。
  3. 观察现象:
    • 系统日志:dmesg 里会出现 Out of memory: Kill process 字样。
    • 应用状态:目标进程是否被 OOM Killer 杀掉。
    • 监控告警:告警是否及时触发。
  4. 恢复验证:故障自动恢复后,检查系统是否自动拉起服务,内存是否回到正常水位。
  5. 记录结果:把 OOM Killer 的日志、进程重启时间、告警延迟都记下来。
关键检查点:
  • OOM Killer 是否杀对了进程?(有时候它会杀掉关键进程,比如 sshd,导致你连不上机器)
  • 被杀的应用是否有自动重启机制?(比如 systemd 或 K8s 的 liveness probe)
  • 告警延迟是否在可接受范围内?

4.4 知识结构:内存故障注入全景图

下面这张图,是我自己梳理的内存故障注入知识结构。你可以把它当作实验前的检查清单。

内存故障注入知识结构 内存故障注入 内存泄漏模拟 内存占用过高 OOM 实验 持续注入小内存块 一次性注入大内存 注入超过可用内存 ChaosBlade mem 命令 --mem-percent / --vm-bytes --timeout / blade destroy top / free -h / dmesg 应用日志 / GC 日志 监控告警 / OOM Killer 日志 验证内存回收机制 验证限流/熔断策略 验证自动恢复能力 核心原则:从小压力开始,逐步加量,全程监控,做好回滚准备

4.5 避坑指南

做内存实验,有几个坑我踩过,分享给你:

  • 别在生产环境直接搞——这不用我说吧?但有人真这么干过。先在预发或测试环境验证。
  • 注意 Swap 的影响——如果 Swap 开着,内存压力会被「稀释」,你注入 80% 可能实际只用了 50% 物理内存。建议实验前 swapoff -a。
  • OOM Killer 可能误杀——我曾经遇到过,注入内存后 OOM Killer 把 sshd 给杀了,结果机器失联。后来我学会了在实验前开一个 tmux 会话,或者用带外管理卡。
  • timeout 别设太短——至少 30 秒以上,给系统足够的反应时间。太短的话,故障还没触发就被撤销了。
重要提醒:如果你在容器环境(Docker/K8s)里做实验,ChaosBlade 默认只影响容器内的内存。但要注意容器的内存 limit 设置——如果 limit 是 512M,你注入 80% 就是 409M,而不是宿主机的 80%。这个细节很多人忽略。