3. CPU故障注入:用stress和mcelog模拟CPU过载与内存校验错误

CPU故障,说白了就是让处理器“生病”。我见过不少团队,系统跑得好好的,一上生产环境就崩。查到最后,往往是CPU扛不住压力,或者内存校验出了岔子。今天咱们就聊聊怎么主动给CPU“找麻烦”,提前把隐患揪出来。

我个人习惯把CPU故障分成两类:一类是过载型,就是CPU被榨干,任务排队、响应变慢;另一类是静默型,比如内存校验错误(ECC Error),表面上看系统还在跑,但数据已经悄悄坏了。这两种,都得测。

3.1 工具准备:stress和mcelog

咱们主要用两个工具。stress负责制造压力,mcelog负责抓取硬件错误日志。嗯,这里要注意,mcelog只对支持ECC内存的服务器有效,普通PC就别指望了。

工具 用途 安装方式
stress 模拟CPU、内存、I/O过载 apt install stress 或 yum install stress
mcelog 记录Machine Check Events(MCE) apt install mcelog 或 yum install mcelog
我的小建议: 在测试机上先跑一遍 stress --help 和 mcelog --help,确认版本没问题。我曾经遇到过stress版本太老,连--cpu参数都不支持,白折腾了半天。

3.2 实验一:CPU过载模拟

这个实验的目标很简单:让CPU使用率冲到100%,看看系统会怎么反应。你想想看,如果这时候你的关键服务还在上面跑,会不会被饿死?

3.2.1 启动压力

用stress启动4个CPU工作线程,持续60秒:

stress --cpu 4 --timeout 60

跑起来之后,用top或htop观察CPU使用率。你应该能看到每个核心都被拉满。我个人习惯同时开一个vmstat 1,看看上下文切换(cs列)和运行队列(r列)的变化。

3.2.2 观察系统行为

压力下的系统,通常会有这些表现:

  • CPU使用率:user%接近100%,idle%接近0
  • 运行队列:r列数值远大于CPU核心数(比如4核机器上r值跑到20+)
  • 上下文切换:cs列数值飙升,可能从几千跳到几十万
  • 响应延迟:ssh操作明显卡顿,敲个命令要等好几秒
关键指标: 如果运行队列(r值)持续超过CPU核心数的5倍,说明系统已经严重过载。这时候任何新增的请求都会被排队,延迟会指数级上升。

3.2.3 避坑指南

我曾经在线上环境不小心多跑了一个stress进程,结果把数据库节点搞挂了。所以,千万别在生产环境直接跑。一定要在测试环境或容器里做。另外,stress默认会一直跑,记得加--timeout参数,或者用stress-ng(更现代的版本)来控制持续时间。

3.3 实验二:内存校验错误模拟

内存校验错误(ECC Error)比CPU过载更隐蔽。系统可能还在运行,但数据已经损坏。mcelog就是用来抓这些“隐形杀手”的。

3.3.1 启动mcelog服务

systemctl start mcelog
systemctl enable mcelog

启动后,mcelog会监听硬件发出的Machine Check Events。你可以用mcelog --client查看实时日志,或者直接看/var/log/mcelog文件。

3.3.2 模拟ECC错误

说实话,纯软件层面很难真正触发ECC错误。但我们可以用stress的内存压力模式,让内存子系统处于高负载,增加硬件出错的概率(如果硬件本身有隐患的话)。

stress --vm 2 --vm-bytes 2G --timeout 120

这个命令会启动2个内存压力进程,每个分配2GB内存并持续读写。跑的时候,同时观察mcelog日志:

tail -f /var/log/mcelog

如果硬件有潜在问题,你可能会看到类似这样的记录:

MCE 0
CPU 0 BANK 1
STATUS 0x8c00004000010090
MCGSTATUS 0
ADDR 0x12345678
MISC 0x86
PROCESSOR 0:0x306c3
TIME 1693123456
SOCKET 0
APIC 0
MICROCODE 0x1e
注意: 如果你在日志里看到“Uncorrected Error”字样,说明发生了不可纠正的内存错误。这意味着数据已经损坏,系统可能已经使用了错误的数据。这种情况必须立即停机更换内存条。

3.3.3 解读mcelog日志

mcelog的日志看起来有点吓人,其实关键字段就几个:

字段 含义 重点关注
STATUS 错误状态码 第62位(0x4000000000000000)表示“Uncorrected Error”
ADDR 出错的内存地址 可以用来定位具体是哪条内存
BANK 内存通道编号 结合主板布局,找到物理插槽
CPU 哪个CPU检测到的错误 多路服务器里,不同CPU可能共享内存控制器

3.4 知识结构图:CPU故障注入全流程

下面这张图,把咱们今天讲的内容串起来了。从工具选择到故障模拟,再到日志分析,一条线走到底。

CPU故障注入实验流程 CPU故障注入实验流程 工具准备 工具准备 stress mcelog CPU过载模拟 内存校验错误 stress --cpu 4 --timeout 60 观察top/vmstat:CPU%、运行队列 stress --vm 2 --vm-bytes 2G 观察mcelog:STATUS、ADDR、BANK 系统响应延迟分析 ECC错误定位与修复 ⚠ 禁止在生产环境直接执行

3.5 实验后的安全机制验证

故障注入不是目的,验证安全机制才是。做完上面的实验,你得回答几个问题:

  1. 监控告警有没有触发? CPU使用率超过阈值时,你的监控系统(比如Prometheus + Alertmanager)有没有发出告警?
  2. 自动恢复机制是否生效? 如果服务因为CPU过载而挂了,进程守护(如systemd、supervisor)有没有自动重启?
  3. 日志是否完整? mcelog的日志有没有被集中采集(比如ELK或Loki)?能不能在出问题时快速检索到?
  4. 降级策略是否有效? 当CPU过载时,系统有没有主动丢弃非关键请求,保护核心业务?
我的经验: 有一次我做完CPU过载实验,发现监控告警延迟了整整5分钟才发出来。查了半天,原来是Prometheus的采集间隔设成了5分钟,而告警规则又用了3次连续采样才触发。你想想看,5分钟延迟,生产环境早出大事了。所以,故障注入之后,一定要验证告警的时效性。

3.6 本章小结

CPU故障注入,说白了就是给系统做“压力测试”和“体检”。stress帮你制造压力,mcelog帮你发现硬件隐患。这两招用好了,很多线上问题都能提前暴露。

我个人建议,把这两个实验加到你的定期巡检脚本里。每个月跑一次,看看系统有没有“亚健康”的迹象。尤其是那些跑了好几年的老服务器,内存颗粒老化、CPU散热不良,都是常见问题。早点发现,早点换,别等到线上崩了再后悔。