虚拟化集群九台虚拟机集体宕机复盘:共享存储APD故障排查与恢复
凌晨两点十三分值夜班的同事在群里扔了三个感叹号财务系统挂了OA 打不开文件服务器连不上整个公司的业务几乎同时停了。我一边套外套一边打开 vCenter那一瞬间只希望是这周运气不好而不是环境彻底崩了。现实比我想象的更狠九台虚拟服务器状态全部异常。在虚拟化环境里待久了我们总爱说“服务器是虚拟的资源是池化的出问题应该比物理机时代少”。可这个凌晨九台明明“看不见”的服务器用最直接的方式提醒我它们可以被虚拟化但业务风险和故障半径一点都没被虚拟掉。下面这篇复盘就是围绕这次“九台虚拟服务器集体罢工”完整还原的排查过程、根因定位和事后沉淀希望对正在做服务器虚拟化、vSphere 集群维护的同行有点参考价值。1. 凌晨的告警风暴九台虚拟服务器同时亮红1.1 我管理的这套虚拟化环境先交代一下背景。公司机房里有三台 x86 物理服务器底层装的是 VMware ESXi版本比较老对应 vSphere Client 6.0.0 来管理。三台物理机组成一个 vSphere 集群上面一共跑了九台业务虚拟机域控、财务数据库、OA、文件共享、邮件网关等。存储方面用一个双控制器磁盘阵列通过 iSCSI 协议把存储池划分给 ESXi 主机格式化成 VMFS 数据存储。这个架构在中小企业里相当典型物理主机有冗余ESXi 主机也有三台看起来“高可用”了。但实际上所有虚拟机的硬盘文件也就是那些 .vmdk全部放在同一个共享数据存储里。也就是说物理服务器是三个坏了其中一台可以用 vSphere HA 把虚拟机拉起但存储只有一个池子这个池子出问题就是所有虚拟机一起出问题。这次事故就是典型。1.2 现象不是一台两台而是九台全凉当天晚上的现象非常明确用户侧完全连不上服务器数据库切不进去文件共享目录打不开OA 登录界面直接超时。我打开 vCenter 客户端看到虚拟机的电源状态还是“已打开”但可访问性已经是“不可访问”主机状态也亮起了黄色告警。尝试打开虚拟机的 Web 控制台屏幕一片黑敲键盘没有任何反应就像操作系统被按了暂停键。第一反应可能是业务系统本身出了问题但九台同时出现同样症状几乎排除了应用程序故障的可能性。它们跑着不同的操作系统、不同的数据库、不同的中间件不可能约好在同一个时间点集体崩溃。所以问题大概率出在它们共同依赖的那一层——虚拟化平台、网络或者存储。物理服务器的前面板指示灯是正常的CPU 和内存负载也没有飙高说明不是物理服务器被压垮了也不是市电断电。但业务就是起不来这才是最棘手的地方。2. 剥洋葱式排查从虚拟层一路查到物理端口2.1 第一层先把网络和“假死活”分清排查的第一步是先确定这九台虚拟机到底是网络不通还是本身就已经“死了”。我用管理网口登到其中一台 ESXi 主机上先验证 ESXi 主机的网络是否正常执行vmkping去测试网关。vmkping -I vmk0 192.168.1.1 -c 5结果网关能通。说明 ESXi 主机自身的管理网络没问题。顺着这条线再想如果主机网络没问题但虚拟机业务访问不了常见原因有三类一是虚拟交换机或者上行链路故障导致数据包进不了虚拟机二是存储断开虚拟机所有磁盘 I/O 全部挂起系统“假死”三是虚拟机内部的网卡配置被人动过。九台一起出问题第三类基本排除所以把重点放在第二层。2.2 第二层数据存储和 I/O 的状态才是关键在一台 ESXi 主机上执行了下面几条命令这一步是整个排查的转折点。esxcli storage filesystem list esxcli storage core device list esxcli storage nmp path list --device naa.xxxxxxxxxxxxesxcli storage filesystem list的输出里数据存储的Mounted和Accessible字段都变成了false。这就很能说明问题了——ESXi 承认这个 VMFS 卷还存在但已经无法访问。再看nmp path list的结果所有存储路径都显示为dead或standby不是正常的active。这里需要解释一个关键概念虚拟机的操作系统只是发出一堆磁盘读写请求但这些请求真正落盘的地方是共享存储上的 vmdk 文件。存储一断虚拟机上的进程不是因为业务代码崩了而停止而是因为底层 I/O 永远得不到响应所有线程都卡在读盘写盘上。从控制台看就是一台“活着的尸体”。这正好印证了那句话服务器是虚拟的但存储和数据的风险是实实在在的。2.3 第三层物理链路与存储设备日志既然 ESXi 和虚拟机之间没有问题问题就必然出在 ESXi 到存储阵列这一段。存储网络用的是独立的 iSCSI 交换机我直接到机柜里看交换机端口状态指示灯亮着但通过esxcli network ip connection list以及存储上查看主机连接状态发现 ESXi 主机虽然能和存储控制器的 IP 保持 TCP 连接但实际的磁盘命令已经没有人应答了。这时候基本可以判断不是网络链路物理断开而是存储阵列本身“瘫了”。登录存储的 Web 管理界面页面能打开但所有磁盘状态刷新非常慢RAID 组的状态也显示异常。更关键的是存储日志里出现了两个控制器之间的心跳丢失记录。也就是说这台双控制器的磁盘阵列其中一个控制器已经变成“假死”状态另一个控制器既没能完成接管也没有对外正常提供服务。所有等待 I/O 返回的 ESXi 主机就这样被晾在半空九台虚拟机同步失去响应。3. 根因落定共享存储“假死”如何把九台虚拟机一起拖下水3.1 存储控制器“假死”到底发生了什么存储阵列的双控制器设计本意是一台控制器故障时另一台能接替它的所有逻辑卷和缓存数据。但这次的问题是控制器一失去响应后控制器二虽然还活着却无法接管对方的缓存因为两个控制器共用的后备电池和缓存镜像链路已经断掉。阵列既不敢丢弃缓存里的数据又没法继续对外提供写服务最终整个存储池进入了“只允许读缓存不响应新写入”的状态。这种“半死不活”的状态比彻底断电更难判断。断电的话ESXi 会立刻识别出目标不可达走超时和故障切换的流程还算干脆控制器假死则会让所有命令像石沉大海ESXi 只能等内部超时一遍一遍重发命令。虚拟机的每一次磁盘读写都变成了一个新的等待队列整个系统的磁盘队列长度满到爆炸表现出来就是九个服务器集体“罢工”。3.2 APD 与 PDL虚拟化里两个容易混淆的“死法”这次事故在 VMware 的故障模型里有一个非常准确的名字APD全称 All Paths Down意思是到存储设备的所有路径都不通了。和它容易混淆的是 PDL全称 Permanent Device Loss意思是设备被永久移除。这两者的区别很关键我整理了一个对照表方便理解。对比项APDAll Paths DownPDLPermanent Device Loss设备状态设备还存在但所有路径无响应设备已被存储系统主动通知“不存在”常见原因存储控制器假死、光纤/网线中断后重新连不通磁盘被拔出、RAID 卸载、LUN 被重新映射ESXi 行为虚拟机继续运行但 I/O 挂起等待超时可以配置是否直接终止虚拟机典型参数Misc.APDHandlingEnable、Misc.APDTimeoutdisk.terminateVMOnPDL对业务的影响像“按了暂停键”业务假死像“拔了硬盘”系统蓝屏或直接关闭这次存储阵列控制器假死就是典型的 APD。默认情况下ESXi 不会在 APD 发生时立刻杀掉虚拟机而是会等一个超时时间超时之后如果开启了 APD 处理虚拟机会被强制关闭。也就是说就算我们当时什么都不做过一段时间虚拟机也会从“假死”变成“真死”但数据丢失的风险会明显增加。3.3 为什么 HA 这次没能力挽狂澜很多刚接触 vSphere 的人会问不是有高可用吗不是有 vMotion 吗不是有 HA 吗为什么九台虚拟机不能自动迁移到别的物理主机答案在于vSphere HA 解决的是“物理主机坏了”的问题而不是“共享存储坏了”的问题。当共享存储处于 APD 状态时三台 ESXi 主机面临的困境是一样的它们都访问不了同一个 VMFS 卷。HA 就算想在其他主机上重新启动虚拟机也得先能读到数据存储里的 vmdk 文件而数据存储本身已经不可用重启虚拟机只会失败。更现实的是如果在存储还没恢复时强制重启还可能遇到主机间的锁冲突造成同一虚拟机被多个主机重复注册。所以高可用不是万能的它只在虚拟化故障模型里覆盖了“计算节点故障”并没有覆盖“存储单点”。排查到这里我还在备用日志里发现了一个小问题vCenter 服务器和 ESXi 主机的时间差了将近四分钟。vCenter 里告警的先后顺序和 ESXi 系统日志对不上给定位问题时间线带来了额外干扰。这是因为之前 NTP 时间服务器配置失效主机时间慢慢跑偏了。虽然它不是事故根因但对排障的影响非常大后面我会单独立一条提醒。4. 恢复战中最容易翻车的三个动作4.1 存储恢复后的重新扫描把存储端的问题处理掉之后不能马上就去开虚拟机。我的做法是先在存储端确认所有 RAID 组已经恢复Online控制器之间的心跳恢复正常然后再回 ESXi 主机重新扫描存储设备。esxcli storage core adapter rescan --all esxcli storage filesystem list esxcli storage nmp path list --device naa.xxxxxxxxxxxx重新扫描之后可以看到数据存储的Accessible状态变成了true存储路径也重新变为active。这一步一定要等存储端彻底稳定再做否则存储刚恢复又抖动虚拟机强制开机反而可能造成文件系统损坏。说白了存储像地基地基没干透楼房不要急着往上盖。4.2 重新注册虚拟机时UUID 和锁文件是最大的坑存储恢复后部分虚拟机在 vCenter 里仍然显示“不可访问”或“无效”。这是因为 APD 期间vCenter 或者 ESXi 已经丢失了对虚拟机配置文件的跟踪需要手动重新注册。重新注册的方法不复杂右键点击主机选择“注册虚拟机”在数据存储浏览器里找到对应的 .vmx 文件按照向导完成注册即可。但这里有一个特别容易翻车的细节注册向导会让你选择“是否重新创建 UUID”。千万要保持原来的 UUID不要勾选重新生成。UUID 一换虚拟机里面的 Windows 激活状态、AD 域信任关系、部分软件授权都可能全部失效。另一个坑是虚拟机目录下可能残留.lck锁文件夹这是上一轮异常关闭留下的产物。需要先确认没有任何一台 ESXi 主机还在使用这个虚拟机再手动删除旧的锁文件否则注册后依然启动失败。还有一个实际遇到的情况某个虚拟机磁盘产生了 delta 增量文件也就是快照残留。直接开机虚拟机会去读增量链一旦增量文件损坏整个磁盘都挂不上。遇到这种情况先在 vCenter 里检查快照管理器如果确定快照已经没有保留价值再执行“整合”操作把增量文件合并回基础磁盘。整合过程对存储 I/O 压力很大九台虚拟机不要同时做一台一台来。4.3 启动顺序和数据一致性检查重新注册完成下一步是启动顺序。我的习惯是“先底座再数据库最后业务”。如果环境里有域控服务器先让域控起来把时间同步和认证服务拉通然后启动数据库服务器因为业务系统百分之百依赖数据库最后再启动 OA、文件共享、邮件网关这些应用层虚拟机。如果顺序反过来应用先启动数据库还没好应用就会报一堆连接异常甚至把连接池打满后面数据库起来了它也不会自动恢复。九台虚拟机全部通电后还要做一次数据一致性检查。Windows 虚拟机的系统日志里如果出现大量disk超时事件建议在确认数据已备份后执行一次磁盘错误检查。数据库服务器要检查事务日志和表完整性宁可多花半小时做校验也不要让带着隐患的业务重新上线。这次的恢复过程里有一个虚拟机因为启动时找不到网卡 MAC 地址导致 IP 冲突查到最后是因为存储离线期间虚拟机被重新注册时生成了新 UUID连带虚拟网卡的 MAC 也被重新分配。手动把网卡 MAC 改回原来的值之后才恢复正常。这种细节只有恢复过的人才知道它有多折磨人。5. 事后复盘虚拟化集群该补的功课我都列出来了5.1 存储拓扑与多路径别把所有的鸡蛋放在一个篮子里这场事故最根本的原因是共享存储成了整套虚拟化环境里的单点。三个 ESXi 主机、九台虚拟机都挂在一台存储阵列上阵列一“假死”整个业务全线瘫痪。虚拟化的好处是把资源池化但坏处也恰恰在这里池子本身一旦出问题故障半径会被放大到池子里所有资源。事后我给这套环境做的改造清单第一条就是解决存储网络的冗余。原来的 iSCSI 四条链路全接在同一台物理交换机上等于把一个已经冗余的架构又变成了单点。正确做法是至少准备两台交换机主机上的两块 iSCSI 网卡分别连到不同交换机上存储的两个控制器也分别连接两台交换机同时开启多路径和端口绑定。这样任意一台交换机或者任意一块网卡故障存储路径都能自动切换虚拟机不会感知到 I/O 中断。5.2 时间服务器与日志时间线排障的地基这次排查过程中vCenter 和 ESXi 时间不同步的问题让我意识到时间同步在虚拟化排障里有多重要。多个告警的先后顺序、事件关联、证书有效性判断全部依赖统一的时间基线。如果时间飘了排障的第一步就已经输了。建议在 vCenter 和每个 ESXi 主机上都配置至少两个 NTP 时间服务器地址。国内常用的时间服务器包括ntp.aliyun.com、ntp.tencent.com、cn.pool.ntp.org等生产环境建议用两个不同厂商的地址避免一个时间源失效后集体跑偏。ESXi 上配置 NTP 可以用下面的命令检查状态。chkconfig ntpd on /etc/init.d/ntpd restart ntpq -p另外如果是在虚拟机里跑 NTP 服务给内网设备做时间源需要注意虚拟机自身的休眠和挂起机制尽量避免因为虚拟化层的时间校准导致时间跳变。时间同步这件事看起来毫不起眼但实际踩坑时能让人怀疑人生。5.3 故障参数、UPS 和演练吃一堑要长一智这次事故还让我重新审视了几个 vSphere 高级参数。针对 APD 和 PDL应该根据业务对 RPO 和 RTO 的要求决定虚拟机的处理方式。如果是核心数据库宁愿让虚拟机关机等待存储恢复也不要让它无限期挂起如果是可快速重建的临时服务器可以设置更短的超时。关键参数是Misc.APDHandlingEnable和Misc.APDTimeout以及disk.terminateVMOnPDL。设置之前一定要在测试环境里验证效果生产环境直接改内核级参数风险很大。还有一个不能忽略的环节是 UPS。磁盘阵列的写缓存依赖电池或者电容保护一旦市电异常导致阵列控制器非正常关机缓存里的数据可能全部丢失甚至引起 RAID 组逻辑损坏。有条件的话给虚拟化环境配上在线式 UPS并让 vSphere 在 UPS 发出关机信号时按顺序优雅关闭虚拟机。别等到存储控制器的缓存坏了再去后悔。最后运维层面一定要做故障演练。我后来在测试环境里做了多次 iSCSI 链路中断演练故意拔掉一根存储链路观察多路径是否自动切换虚拟机是否全程无感知。练完之后才发现真正的冗余不是写在拓扑图上而是每次拔线之后业务还能正常跑。虚拟化是一个把物理风险集中化的技术它不会消灭故障只会改变故障的表现形式。九台服务器同时“罢工”这种场景一次就够让人长记性了。