第二章:故障模式分析

大家好,我是老张。今天咱们聊聊故障模式分析。

做交易系统这么多年,我最大的体会就是:故障一定会来,只是时间问题。你想想看,一个每秒处理几万笔订单的系统,怎么可能永远不出问题?

我个人习惯,在设计阶段就把可能出故障的地方列出来。这叫「故障模式分析」。说白了,就是提前想好「哪里会坏、坏了会怎样、怎么应对」。

2.1 常见故障类型

交易系统常见的故障,我归纳为四大类。嗯,这四类我都踩过坑。

2.1.1 网络故障

网络故障是最常见的,也是我最头疼的。为什么?因为它的影响范围太大了。

  • 网络分区:交换机挂了、光纤断了,集群被分成两半
  • 延迟抖动:平时1ms的延迟,突然变成500ms
  • 丢包重传:TCP重传导致请求堆积
  • 带宽打满:某个服务疯狂发数据,把带宽吃光了
我的经验:网络故障最难排查。我曾经遇到一个诡异问题——交易系统每隔15分钟卡顿一次。查了三天,最后发现是交换机的STP(生成树协议)在周期性收敛。从那以后,我养成了一个习惯:所有网络设备必须关闭STP

2.1.2 磁盘故障

磁盘故障,说白了就是「读写不了数据了」。交易系统对磁盘的依赖其实比想象中大——日志、数据库、消息队列,哪个离得开磁盘?

  • 磁盘损坏:物理坏道、磁头故障
  • IO延迟飙升:磁盘队列深度过大,读写卡住
  • 磁盘空间满:日志没清理,直接把磁盘撑爆了
  • 文件系统损坏:异常断电导致文件系统元数据损坏
避坑指南:我曾经遇到过磁盘空间满了,但监控没报警——因为监控日志也写不进去了。这是个典型的「监控盲区」。现在我的做法是:监控系统必须独立存储,不能和被监控的服务共用磁盘。

2.1.3 CPU故障

CPU故障,通常不是硬件坏了,而是被某个进程吃光了

  • CPU 100%:某个线程死循环,或者GC频繁触发
  • 上下文切换过高:线程数太多,CPU都在忙着切换线程
  • CPU降频:散热不行,CPU自动降频保护
  • NUMA问题:跨CPU访问内存,延迟暴增

我记得有一次,线上交易延迟突然从2ms飙到200ms。查了半天,发现是JVM的GC线程把CPU吃满了。为什么?因为堆内存设置太大了,GC一次要扫几十GB。嗯,这是个典型的「配置不当」问题。

2.1.4 内存故障

内存故障,最怕的就是OOM(内存溢出)。交易系统对内存的依赖极高——缓存、订单状态、行情数据,全在内存里。

  • 内存泄漏:对象创建了不释放,慢慢把内存吃光
  • 内存碎片:频繁分配释放,导致大块内存分配失败
  • Swap使用:内存不够了,开始用磁盘当内存,性能直接崩
  • 堆外内存溢出:DirectBuffer、mmap等堆外内存泄漏
核心观点:内存故障的可怕之处在于——它往往是渐进式的。今天内存占用80%,明天85%,后天90%...你看着监控曲线慢慢往上爬,但就是找不到原因。等到了99%,系统突然挂了,你才反应过来——哦,泄漏了。

2.2 故障影响评估

故障来了,影响有多大?这不能靠猜。我建议用「故障影响矩阵」来量化评估。

故障类型 影响范围 影响程度 恢复时间 业务损失
网络分区 全集群 严重 分钟级 订单丢失、重复
磁盘损坏 单节点 中等 小时级 数据丢失风险
CPU 100% 单进程 中等 分钟级 延迟升高
内存OOM 单进程 严重 分钟级 服务不可用

你看这个表格,每个故障都要评估四个维度:

  1. 影响范围:是单个节点,还是整个集群?
  2. 影响程度:是轻微抖动,还是完全不可用?
  3. 恢复时间:需要多久才能恢复?
  4. 业务损失:会造成订单丢失、重复,还是延迟?

我个人习惯,把故障分成三个等级:

  • P0(致命):系统不可用,订单无法处理。必须立即响应。
  • P1(严重):功能受损,但核心交易还能跑。需要快速处理。
  • P2(一般):延迟升高,但业务不受影响。可以慢慢修。
我的建议:不要把所有故障都当成P0。你想想看,如果每个故障都拉警报,运维人员会疲劳的。真正到了P0的时候,反而没人重视了。这就是「狼来了」效应。

2.3 故障演练方法论

故障演练,说白了就是主动搞破坏。在可控的环境里,模拟各种故障,看看系统能不能扛得住。

我参与过几十次故障演练,总结了一套方法论:

2.3.1 演练准备

  • 确定演练目标:这次要验证什么?是网络容错,还是磁盘容错?
  • 选择演练环境:最好用生产环境的影子集群,或者全量复制的测试环境
  • 制定回滚方案:万一搞砸了,怎么恢复?这个必须提前想好
  • 通知相关人员:让运维、开发、业务都知道「我们要搞事情了」

2.3.2 演练执行

我常用的故障注入工具:

  • ChaosBlade:阿里开源的混沌工程工具,支持CPU、内存、网络、磁盘等故障注入
  • tc(Traffic Control):Linux自带的网络模拟工具,可以模拟延迟、丢包、带宽限制
  • stress:Linux压力测试工具,可以压CPU、内存、IO

举个例子,模拟网络延迟:

# 对eth0网卡增加100ms延迟
tc qdisc add dev eth0 root netem delay 100ms

# 模拟10%的丢包率
tc qdisc add dev eth0 root netem loss 10%

# 清理模拟
tc qdisc del dev eth0 root
注意:千万别在生产环境直接跑这些命令!我见过有人手滑,在生产环境加了网络延迟,结果整个交易系统卡了5分钟。嗯,那个人后来被调去写文档了。

2.3.3 演练复盘

演练完了,一定要复盘。我习惯用「5W1H」法:

  • What:发生了什么故障?
  • When:什么时候发生的?
  • Where:影响到了哪些服务?
  • Why:为什么会出问题?
  • Who:谁发现了?谁处理的?
  • How:怎么恢复的?花了多久?

复盘的目的不是追责,而是找到系统的薄弱点。每次演练,至少会发现1-2个之前没想到的问题。

2.4 知识体系总览

下面这张图,是我对本章内容的总结。你可以把它当成一个「故障模式分析」的思维导图:

故障模式分析 网络故障 网络分区、延迟抖动 丢包重传、带宽打满 磁盘故障 磁盘损坏、IO延迟飙升 磁盘空间满、文件系统损坏 CPU故障 CPU 100%、上下文切换过高 CPU降频、NUMA问题 内存故障 内存泄漏、内存碎片 Swap使用、堆外内存溢出 故障影响评估 P0/P1/P2分级 故障演练方法论 准备 → 执行 → 复盘

这张图把本章的核心内容串起来了。你仔细看:四大故障类型是基础,故障影响评估是判断标准,故障演练方法论是验证手段。三者缺一不可。

最后说一句:故障模式分析不是一次性的工作。系统在变,业务在变,故障模式也在变。我建议每半年做一次全面的故障模式分析,把新发现的问题加进去,把已经解决的问题划掉。这样,你的系统才会越来越健壮。

公众号:蓝海资料掘金营,微信deep3321