集群高可用方案通常先把应用节点做成多副本,再通过负载均衡和故障转移降低单台服务器宕机的影响。但实际故障复盘里,存储链路和供电链路往往比计算节点更容易成为全局性单点。一个双控制器存储如果只走一条FC链路,或者两个电源模块都插在同一路PDU上,集群节点再多也挡不住一次中断。因此消除单点故障要同时覆盖网络存储和电源供应,而不能只盯着应用进程是否存活。

一、为什么单点故障总出现在存储与供电路径
集群通过多节点方式解决了应用层单点,但共享存储设备、存储网络交换机、HBA卡以及电力输入仍然是集中式组件。计算节点可以随意增加,存储阵列如果只有一台,并且没有双控制器,一旦控制器固件异常、缓存电池失效或主板故障,所有集群节点都会同时失去数据访问能力。这不是概率问题,而是架构上的集中依赖问题。
存储网络的单点更容易被忽略。很多部署使用双控制器存储,却在服务器上只配置一块HBA,或者只连接一台光纤交换机。这样存储控制器虽然冗余,但服务器到存储的路径仍然是单条。链路抖动、光模块老化、交换机端口故障或线缆被误拔,都可能导致I/O超时,最终触发集群隔离或虚拟机重启。
供电链路同样如此。服务器内部通常配置了双电源模块,但如果两个电源模块都插在同一个PDU上,或者两个PDU最终接到同一路市电,那么一次空开跳闸就会同时切断两路输入。更隐蔽的是,部分机柜只配置了一路UPS输出,即便服务器看到两个电源模块正常,实际上它们并不具备独立故障域。因此电源冗余不能只看电源模块数量,还要追溯从服务器到市电的完整链路。
二、网络存储冗余:从多路径到双控制器落地
网络存储冗余的第一步是让每台服务器通过至少两条独立物理路径访问存储。以iSCSI为例,服务器应当配置两张独立的以太网卡或两块HBA,分别接入两台不同的存储交换机。存储阵列的两个控制器也分别连接到这两台交换机。这样任意一条链路中断,I/O仍然可以通过另一条路径继续传输。仅完成物理连线还不够,操作系统必须启用多路径软件,否则系统中会看到两个重复的磁盘设备,反而容易造成写入冲突。
Linux环境通常使用device-mapper-multipath来聚合多路径。安装后需要调整multipath.conf,设置合适的路径选择策略。对于多数双控制器存储,使用round-robin策略可以在两条路径之间轮询发送I/O,既提升吞吐,又能在单路径故障时快速切换。下面的配置示例将路径分组策略设为multibus,并启用立即故障恢复。
# 安装并启用 multipath 服务 yum install -y device-mapper-multipath systemctl enable --now multipathd # 查看当前聚合后的多路径设备 multipath -ll mpathb (3600a0980000000000000000000000001) dm-3 VENDOR,PRODUCT size=2.0T features='1 queue_if_no_path' hwhandler='0' wp=rw `-+- policy='round-robin 0' prio=1 status=active |- 1:0:0:0 sdb 8:16 active ready running `- 2:0:0:0 sdc 8:32 active ready running
上面输出中的mpathb就是聚合后的多路径设备,它下面挂载了sdb和sdc两条物理路径,状态均为active ready running。应用读写应当使用/dev/mapper/mpathb,而不是直接使用sdb或sdc。否则一旦sdb对应的链路中断,应用仍然会报I/O错误,多路径就失去了意义。
# /etc/multipath.conf 片段
defaults {
user_friendly_names yes
find_multipaths yes
path_selector "round-robin 0"
failback immediate
}
blacklist {
devnode "^sd[a-z]$"
}
这段配置会禁用本地磁盘等非存储设备进入多路径管理,避免将系统盘误识别为多路径设备。对于FC SAN、SAS或iSCSI,具体厂商可能提供更精细的配置建议,但核心原则一致:所有到共享存储的路径都要被识别、聚合和监控。存储侧还要确认双控制器工作在双活或ALUA模式,而不是主备模式下切换时间过长。双活控制器能够同时处理I/O,切换几乎无感;主备模式虽然也能冗余,但切换时可能存在数十秒甚至更长的中断。
如果集群规模较大,还可以进一步引入分布式存储,将数据副本分散到不同节点和不同机架。Ceph、GlusterFS等方案能够在存储层直接消除单控制器问题,但这也要求网络拓扑和机架分布足够合理,否则两个副本落在同一个电源故障域,冗余效果会大打折扣。
三、电源冗余设计:双路PDU、ATS与UPS联动
服务器电源模块冗余只是电力保障的最后一环。真正可靠的供电架构需要从市电输入开始规划。理想情况下,机柜配置A、B两路PDU,分别来自不同的配电单元,最好由不同的市电变压器供电。服务器双电源模块分别插入A、B PDU,存储阵列、光纤交换机、以太网交换机等关键设备也同样采用双电源接入。这样任何一路市电掉电,设备都不会整体断电。
对于只有单路市电机房,可以在前端增加ATS自动转换开关,配合UPS和发电机实现市电中断后的自动切换。ATS切换过程通常存在几十毫秒到几秒的断电间隙,因此关键设备自身必须支持双电源输入,或者后端配置在线式UPS来覆盖切换间隙。在线式UPS始终由电池逆变输出,市电断电时电池直接接管,没有切换时间,适合存储控制器、核心交换机等敏感设备。
UPS不能只当作应急电池使用,还应当接入监控系统,实现电力事件触发业务动作。NUT是Linux下常用的UPS监控工具,它可以通过串口或网络读取UPS状态,并在市电中断且电池电量低于阈值时执行安全关机脚本。下面是一个upsmon配置示例。
# /etc/nut/upsmon.conf 关键配置 MONITOR mainups@192.168.1.50 1 monuser secret slave SHUTDOWNCMD "/sbin/shutdown -h +0" NOTIFYCMD "/usr/local/bin/ups-notify.sh" NOTIFYFLAG ONBATT SYSLOG+EXEC NOTIFYFLAG ONLINE SYSLOG+EXEC
当UPS进入ONBATT状态,也就是市电中断由电池供电时,NOTIFYCMD会触发自定义脚本发送告警。管理员可以在脚本中先关闭非核心服务、暂停备份任务、降低存储同步频率,延长电池续航。真正到了电池低电量状态,SHUTDOWNCMD才会执行关机,避免突然断电损坏文件系统。
电源冗余的另一个常被忽视的细节是负载平衡。双路PDU应该尽量均衡分配设备,避免一路负载过高。某些服务器电源模块可以在管理界面查看当前输入功率,也可以通过带外管理命令快速检查。
# 查看服务器电源模块状态 ipmitool sdr type "Power Supply" # 查看双路输入状态 ipmitool chassis status | grep -i power
这些信息应当纳入日常巡检,而不是等到断电时才发现某一路电源模块早已失效。很多故障案例中,服务器双电源模块在硬件层面一直存在冗余,但其中一块电源模块已经损坏数月,因为没有监控而未被发现。真正市电掉电时,剩余那块电源又因负载过高触发保护,最终导致整机宕机。
四、故障切换验证与持续巡检
冗余配置只有在真实故障中验证过,才能认为是可用的。设计阶段看起来完整的双路径、双电源,实际部署中可能因为线缆插错、策略未加载或监控未配置而失去效果。因此集群上线后必须做故障注入测试,模拟拔掉一条网络线缆、断开一路PDU、重启一个存储控制器、关闭一台光纤交换机等场景,观察业务是否无感切换。
存储多路径切换是最常见的测试项目。测试前可以先记录当前I/O路径数量,拔掉一路链路后再次查看,确认活跃路径减少但I/O没有中断。下面的脚本可以持续监测多路径设备中的活跃路径数量,低于阈值时输出告警,适合在测试期间或日常巡检中使用。
#!/bin/bash
# 监控多路径活跃路径数量,低于阈值时告警
while true; do
active=$(multipath -ll | grep -c "ready running")
if [ "${active}" -lt 2 ]; then
echo "$(date '+%F %T') 活跃路径不足: ${active}"
fi
sleep 10
done
测试时还应该关注切换时间。多路径协议的路径检测周期、存储控制器的故障切换策略、SCSI命令超时时间都会影响业务感知。对于数据库等高I/O敏感性服务,即使几秒钟的I/O阻塞也可能拖垮连接池。因此需要根据集群实际业务调整multipath的polling interval、no_path_retry等参数,而不是直接使用发行版默认值。
电源切换测试同样需要验证完整链路。可以按计划关闭A路PDU,观察服务器、存储和交换机是否仍然在线。然后恢复A路,再关闭B路。测试时重点观察UPS告警脚本是否触发,集群是否出现节点失联,虚拟机是否发生迁移。若发现某些设备没有接入双路电源,或者某一路电源模块状态异常,应立即整改。只有把冗余从配置清单变成可验证、可监控的日常能力,集群单点故障才真正被消除。