
凌晨两点四十分手机在床头柜上连续震动了差不多半分钟。我迷迷糊糊点开运维群里的监控截图一整屏红色告警——9台服务器集体失联业务系统报障、数据库连接超时、文件服务无响应。值班同事在群里打了一行字“是不是机房挂了”那一瞬间我脑子里闪过的是供电故障、空调停摆、交换机烧毁这类物理层灾难。但等我们赶到机房物理机指示灯全亮着存储阵列硬盘灯也在正常闪烁。真正出问题的是另一层完全不直观的东西——这9台“服务器”其实是跑在虚拟化平台上的虚拟机。它们是虚拟的可那一刻带来的惊魂实实在在让全组人后背发凉。1. 凌晨两点四十分9台虚机“假死”监控大屏全红1.1 告警风暴的第一现场当时监控平台的告警面板大致是这么一张列表告警项告警内容告警级别VM-ERP01ICMP不可达SSH连接超时严重VM-OA01服务无响应连接池溢出严重VM-DB01数据库会话阻塞IO写入超时严重VM-FILE01SMB共享访问超时严重VM-MES01应用进程假死端口无响应严重VM-GW01ping不通管理通道断开严重其余3台业务端口无响应CPU占用下降严重一眼看过去9条告警没有一条是“虚机状态变成关机”的全是“不可达”“超时”“无响应”。这个细节当时我没太在意后来复盘才发现它已经把答案写在脸上了——不是死机是假死。值班同事已经尝试过SSH登录反馈是“能连上但敲个命令要等好几秒dmesg刷出来一堆IO错误”。应急群里有人问“要不要强制重启一下”我拦住了。原因很简单9台虚机同时出问题而且都是同一类症状重启单台虚机大概率没用甚至可能让情况更糟。1.2 虚机“还活着”但已经无法服务了做虚拟化运维的人迟早会面对一个概念假死。它和传统意义上的宕机完全不同。状态类型表象常见原因死机虚机状态变为关机/重启业务彻底中断系统崩溃、宿主机故障、人为误操作失联ping不通、远程登录失败网络层面直接消失虚拟交换机故障、网卡配置错误、链路断开假死能ping通或勉强登录但SSH卡顿、服务无响应、IO不返回块存储IO卡死、内核阻塞、资源耗尽当时9台虚机是“假死失联”混合状态。少数几台连ping都不通是因为文件系统卡死之后网络协议栈也连带僵住了。绝大多数虚机的进程都还活着CPU和内存占用也在可业务就是推不动。这种状态最折磨人。它不像物理机宕机那样有一个明确的重启按钮可以按也不像网络断开那样能顺着链路去查。虚机看起来就在那里但任何操作都像跟一尊雕塑说话——它不回你你也叫不醒它。凌晨四点站在机房里面对这种“活死人”状态是最容易让人上头的时候。2. 排查路线图网络、负载、时间同步挨个过到底谁在撒谎2.1 为什么先查宿主机而不是虚机复盘的时候我们画过一张排查顺序表现在看依然是对的排查顺序排查对象判断方法常用命令1物理网络ping网关、检测丢包ping / mtr2宿主机负载CPU、内存、磁盘IOtop / vmstat / iostat3存储链路控制器状态、多路径路径数multipath -ll / 存储管理界面4虚拟化平台虚机状态、虚拟交换机virsh list / esxcli5虚机内部进程、日志、时间同步dmesg / systemctl / chronyc核心逻辑是9台虚机分布在多台宿主机上但它们共享同一套物理资源包括网络链路、存储链路和虚拟化平台本身。如果它们在同一个时间窗口内全部出问题概率上指向的一定是共享层被击穿而不是9台虚机各自在同一分钟里得了不同的病。打了个比方给团队的小朋友听一栋楼的居民同时说家里断网你第一反应是查楼栋交换机和入户线路而不是挨家挨户重启路由器。这个道理放到虚拟化环境里就是“先查底座再查虚机”。2.2 一轮排查下来虚机内部的CPU、内存都正常但IO读写全部卡住我们先跑了一遍宿主机层面的检查。三台宿主机CPU也不高、内存也不紧张看起来都挺健康。但一登进虚机内部画风就完全不对了。只见top命令刷出来一堆进程处于CPU和内存占用都很低但几乎没有进程在推进。iostat -x 1一看await数值高得离谱%util直接打满100%。这里的异常信号非常典型上层计算资源充足但虚拟磁盘的IO请求发出去之后没人响应。再翻虚机里的dmesg满屏都是类似这样的关键词[12345.678901] INFO: task mysqld:1234 blocked for more than 120 seconds. [12345.678901] blk_update_request: I/O error, dev vda, sector 2048000“blocked for more than 120 seconds”是内核hung task检测机制触发的告警意思是进程已经在不可中断睡眠状态下等待IO超过两分钟。这个状态让所有业务停摆数据库写不了日志应用连不了连接池文件服务目录都列不出来。这个时候我基本可以断定问题不在虚机自身而是虚机后端依赖的存储块设备链路出了状况。虚机内部的virtio-blk前端驱动就像小区门口的门禁门禁本身没问题问题是门口那条路被堵死了所有要出门的人只能干等着。2.3 宿主机和存储的异常信号我们把目光转向存储链路。磁盘阵列管理界面打开的一瞬间答案基本就摆在脸上了阵列的B控制器因为温度过高触发了保护机制自动离线所有IO由一个A控制器接管。存储阵列管理界面上A控制的CPU占用率和IO队列深度已经红到发紫。再切到宿主机上跑一条multipath -ll发现路径数从正常情况下的4条掉得只剩2条还有一条处于failed状态。这一下所有的线索都串起来了。9台虚机的虚拟磁盘全部放在这台磁盘阵列的同一个LUN组上。存储控制器先趴掉一个剩下的那个又被超载的IO请求灌满链路质量再打个折扣最终结果就是9台虚机集体“罢工”。有意思的是当时监控平台上关于存储的告警其实已经报了但被淹没在一大堆虚机告警里值班同事根本没注意到。这也是一个非常深刻的教训底层的先兆信号往往会被上层的故障风暴掩盖。3. 元凶浮出水面存储控制器“半残”多路径没有兜住底3.1 多路径冗余为什么没有生效先把多路径的基本概念讲清楚。iSCSI磁盘阵列通常配备双控制器每个控制器又有独立的iSCSI入口所以一台宿主机连接同一块LUN时通常会有4条路径。多路径软件的作用就是把这几条物理路径聚合起来提供冗余和负载均衡。理想情况下一条路径断了IO会自动漂移到其他健康路径上应用无感知。当时我在宿主机上看到的实际输出是这样的$ multipath -ll mpathc (3600...abc) dm-2 Vendor,Model size1.0T features1 queue_if_no_path hwhandler0 wprw -- policyround-robin 0 prio1 statusactive |- 5:0:0:1 sdb 8:16 active ready running |- 6:0:0:1 sdc 8:32 active ready running - 7:0:0:1 sdd 8:48 failed faulty running注意看原本应该4条路径现在只剩2条是active状态其中一条还标着failed。而且B控制器完全失联也就是说存储端实际只剩“一条半腿”在支撑全部IO。这里暴露了多路径配置上的一系列问题。首先路径检测间隔太长B控制器离线之后系统没有及时感知其次没设置failback为immediate路径恢复后不会自动切回长期运行下来路径拓扑已经乱了最后上层IO超时时间与多路径的no_path_retry参数不匹配导致故障期间的IO重试行为完全失控。3.2 “IO重试风暴”是怎么把9台虚机一起憋死的光有路径减少还不足以让9台虚机全部卡死。真正的连锁反应发生在B控制器离线之后的那几分钟里B控制器失联本应均衡分配到两条控制器上的IO请求瞬间全部压到A控制器A控制器自身的一个iSCSI入口也存在光模块劣化问题链路“半通不通”部分请求超时多路径软件不会直接拒绝超时的IO而是触发SCSI层重试重试请求排队进入A控制器的IO队列而A控制器的处理能力已经被灌满最终形成IO重试风暴越是超时重试越多重试越多A控制器越忙A控制器越忙虚机的IO越等不到结果用大白话解释就像一条高速因为事故只剩一条车道所有车都挤过来还有一批车反复倒回入口重新上高速直接把入口也堵死了。虚机里的进程全部进入D状态任何业务都推不动但表面上看起来虚机一切正常。这个阶段最恐怖的地方在于如果你在宿主机上用virsh list看所有虚机都是running状态。可如果你试图重启其中一台虚机会发现它根本起不来——因为虚机启动时需要读写虚拟磁盘而磁盘IO的链路并没有恢复。重启不仅没帮助还会给已经超载的A控制器再添一把火。3.3 时间服务器在这里插了一脚排查过程中还有一个差点让我们误入歧途的插曲——几台虚机的系统日志时间轴对不上有的快了三四分钟有的慢了一两分钟。一开始我们以为是故障蔓延的时间顺序记录错了后来才发现是虚机时钟漂移造成的。虚拟化环境里的时钟漂移比物理机更明显。虚机的时钟是基于宿主机时钟模拟出来的宿主机负载波动、CPU电源管理策略都会让虚机时钟偏离真实时间。如果虚机内部没有配置时间同步或者上游时间源不可达时间就会越漂越远。当时这个问题的破坏力在于它让我们在判断“哪台虚机先挂、故障是怎么扩散”的时候多花了将近一小时。日志时间错乱前后顺序根本对不上Kerberos认证和数据库同步也因此出现了一些诡异的偶发失败。后来我们统一改了时间同步配置这个干扰才算彻底消除。4. 复盘虚拟化平台里四个看不见的单点4.1 存储链路冗余不等于高可用这次事故最扎心的地方在于架构图上的设计明明是“双控制器多路径”的冗余方案结果还是集体罢工了。原因很简单冗余只是“存在”没有人周期性验证它是否真的可用。复盘时翻记录发现B控制器之前就有过温度偏高的告警但被当成了“设备正常波动”。多路径虽然配了但从来没人试过真正拔掉一路光纤看它能不能自动切换。路径检测参数用的全是默认值针对这套阵列的最优配置完全没有调过。建议每季度做一次存储链路故障演练。低峰期在存储端断开B控制器的iSCSI链路观察多路径在预期时间内完成切换、虚机IO无感。如果切换时间超过几秒就要回头检查path_checker、failback配置以及应用层是否配置了足够长的SCSI超时时间。这比买一堆冗余硬件却从不验证要有用得多。4.2 虚机层面的告警掩盖了底层故障监控大屏上一片红是因为我们监控的大多是业务层和虚机层指标ping不可达、端口不通、服务无响应。这些当然重要但它们都是“结果指标”不是“原因指标”。结果指标只能在故障已经爆发之后告诉你“出事了”原因指标才能在故障爆发之前告诉你“要出事”。真正应该盯的是下面这些监控指标建议阈值告警作用存储控制器健康状态温度、电池、控制器active状态异常即告警提前发现控制器隐患多路径有效路径数量低于正常值立即告警在虚机受影响之前发现链路故障iSCSI会话数低于预期会话数告警识别存储连接中断存储交换机光功率低于阈值告警预警光模块劣化虚机IO等待时间持续超过500ms告警定位存储性能瓶颈这次事故之后我们把每台宿主机的multipath有效路径数量做成了一个自定义监控项只要有路径失效告警立刻推到值班群。这样下次再遇到类似问题会在虚机集体“罢工”之前就收到预警而不是对着满屏红色告警干瞪眼。4.3 应急预案里少了“假死”这一项翻遍既有应急SOP写的基本都是“虚机宕机→重启虚机”“宿主机宕机→重启宿主机”“网络故障→检查交换机”。唯独没有“虚机假死”的专项处置流程。假死场景下重启虚机往往是最差的选择。虚机启动时一样要访问虚拟磁盘如果底层IO链路没有恢复重启只会加剧存储控制器负载甚至可能导致虚拟磁盘文件系统异常。正确的处置优先级应该是先恢复存储IO链路——这通常等于恢复一切让虚机内部的IO超时自然解除观察业务是否自动恢复如果虚机内部已经完全僵死在宿主机层面对该虚机做一次常规关机最后才考虑强制重启或者迁移这个优先级顺序是这次事故用一整夜惊魂换回来的。后来我们把它写进了新的SOP放在最显眼的位置。4.4 光模块和线缆是最容易被忽视的物理层排查过程中我们一度怀疑是光纤被老鼠啃了后来查出来是存储交换机一个光口的光功率偏低链路有错误计数但没完全断开。这种“半通不通”的状态比完全断开更麻烦因为上层协议会把它当成“稍微慢一点”不会触发链路断开告警却会积累大量重传和超时。现在我们的设备全部纳入了带外监控光模块温度、光功率、错误计数都汇总到统一监控平台。这里要提醒一句随着机房设备密度提升散热环境和过去完全不一样了光模块这类部件的工作温度区间更窄更容易出现热劣化。不要以为光模块是免维护的它们和硬盘一样是会老化的。5. 落地整改这次事故后我们给平台上的四道保险5.1 多路径配置逐台核查事故后第一件事把所有宿主机的多路径配置拉出来逐一比对。重点检查这几个参数$ cat /etc/multipath.conf defaults { polling_interval 5 path_checker tur failback immediate no_path_retry 18 user_friendly_names yes }polling_interval设为5秒太长了感知不到故障path_checker用tur对大多数存储阵列兼容性最好failback设为immediate路径恢复后立即切回避免长期跑在单控制器上no_path_retry要结合上层SCSI超时设置评估不能拍脑袋填再配合一个定时任务把multipath -ll的输出和路径数量发到监控平台问题出现的第一时间就知道而不是等虚机卡死了才手动敲命令。5.2 把存储面纳入统一监控之前存储阵列的监控是独立系统管理界面开着才能看到状态。现在通过SNMP和API把存储控制器状态、温度、IO负载全部同步到统一监控平台B控制器一离线告警立刻推进值班群。存储交换机端口的光功率和错误计数也加了监控。这一项很快就产生了价值帮我们提前排查出好几个劣化光模块都是还没彻底故障但已经在疯狂重传的那种。这种“提前半拍”的发现以前是想都不敢想的。5.3 重写应急SOP从“重启虚机”改为“先救IO”SOP核心变化就一句话任何多台虚机同时异常的情况一律先检查存储和多路径再动虚机。存储链路检查被列为紧急处置第0步优先级高于一切。新SOP里固化了这么一套快速命令# 宿主机侧 ssh roothost01 multipath -ll # 查看有效路径数量 multipath -r # 重新加载多路径配置 iscsiadm -m session --rescan # 重新扫描iSCSI会话 # 存储侧Web界面/CLI # 查看控制器状态、端口状态、LUN映射状态这套命令后来在一次小规模演练中发挥了作用人工介入时间从原来的半小时压缩到了五分钟以内。工具还是那些工具关键是顺序对、动作快。5.4 时间同步的冗余部署时间漂移这件事也许不会直接让虚机宕机但它会在关键时刻让排查彻底乱套。我们统一在每台宿主机和每台虚机里部署了chrony上游配了至少两个内网时间源和一个外网备份时间源。有一点要特别注意宿主机和虚机不要共用同一个时间源否则上游时间源故障时会一损俱损。另外虚机时钟漂移的隐性危害往往比显性危害更大——备份任务的时间窗口错乱、审计日志的时间戳对不上、会话票据提前过期。这些琐碎的异常背后可能都是时钟漂移在捣乱。6. 写在最后服务器是虚拟的故障的边界反而更模糊了这次凌晨的惊魂让我彻底想明白了一个道理虚拟化给运维带来的最大改变不是节省了多少物理机而是故障的边界变得极其模糊。物理机时代一台机器出问题边界很清楚重启、换件、隔离动作干脆利落。虚拟化时代9台虚机同时“罢工”你根本不知道该对着虚机使劲还是对着宿主机使劲还是该跑到机房里看存储。虚机是虚拟的但业务中断带来的惊魂是实实在在的——每一台虚机背后都是一摊真实的业务每一个D状态进程背后都是等着结转的报表、等着下单的销售、等着审批的领导。我个人的经验是虚拟化平台运维把“底层依赖”看得比“虚机本身”更重要。多路径是冗余的但也是要定期练的存储是双控的但也是会老化的时间同步看着不起眼关键时刻能让你连日志都对不上。所谓高可用是演练出来的不是写在架构图上的。最后分享一个小技巧遇到类似“多台虚机同时异常”的情况先别急着点重启先在宿主机上敲一条multipath -ll。这条命令往往比你在虚机里翻半天日志有用得多。如果你想更稳一点就把这条命令写进监控告警脚本让它替你在虚机“罢工”之前发现问题。