火灾预警后需用virsh安全批量关机:严格限并发(如parallel -j 8)、每台后sleep 0.3、用virsh list --name --all取名、以virsh domstate轮询确认“shut off”、单台超时90秒则降级destroy,脚本分发至各宿主机本地执行。

火灾预警触发后,如何用 virsh 安全批量关机而不卡死宿主机
数据中心火灾报警联动系统通常会通过 SNMP、HTTP webhook 或串口信号通知管理节点。一旦收到预警,脚本必须在断电前 2–5 分钟内完成虚机停机——但直接并发调用 virsh shutdown 数千次极易压垮 libvirt 进程或宿主机 CPU,导致部分虚机卡在 “shutting down” 状态。
- 关机命令必须用
virsh shutdown(非virsh destroy),避免数据丢失;virsh shutdown依赖客户机内运行的acpid或 systemd-logind,提前确认虚机已启用该服务 - 严格限制并发数:用
parallel -j 8或 shell 的wait+ 子 shell 控制同时执行不超过 10 个virsh shutdown请求,libvirt 默认只处理约 15 个并发连接,超限会返回Failed to connect to libvirt - 每台虚机关机后加
sleep 0.3,缓解 dbus 和 polkit 压力;实测不 sleep 时,300 台以上虚机集中触发会导致部分宿主机 dbus-daemon 卡住 - 避免用
virsh list --all | awk '{print $2}'解析输出——列宽不固定,$2 在虚机名含空格时失效;改用virsh list --name --all,它输出纯名称,每行一个
怎么判断虚机是否真正关机完成,而不是假死在 shutdown 状态
virsh list 显示 “shut off” 才算安全,而 “running” 或空白状态都不可靠;但有些虚机因内核 hang 或 acpid 未响应,会长期卡在 “running” 状态,virsh shutdown 实际已无作用。
- 轮询检查必须用
virsh domstate <var>vm_name</var>,它输出精确状态(如running、shut off、paused),比virsh list解析更可靠 - 设置超时:单台虚机等待上限设为 90 秒,超过则降级执行
virsh destroy;注意virsh destroy是强制断电,仅用于兜底 - 不要依赖
ping或 SSH 探活:虚机网络栈可能早于用户态进程挂掉,ping 得通但domstate仍是 running,说明只是内核还在跑,应用早已不可用
脚本如何适配不同宿主机集群,避免单点故障
不能把所有虚机列表硬编码在一个控制节点上——万一这个节点先断电,整个关停流程就中断。实际部署需分层:
- 虚机清单按宿主机分组,存为每个宿主机本地的
/etc/vm-list.txt(内容仅为虚机名,一行一个),避免 NFS 或数据库单点依赖 - 控制脚本推送到每台宿主机,由本地 cron 或 systemd timer 触发;火灾信号通过广播包(如
logger "FIRE_ALERT"+ rsyslog 过滤)或轻量 MQTT 订阅分发,不依赖中心调度器 - 每台宿主机独立执行关停,完成后向中央日志服务器写入
echo "$(date) $(hostname) done" >> /var/log/shutdown-finish.log,便于事后审计哪台没完成 - 若某宿主机失联(比如网卡已断),其他宿主机继续执行,不互相等待
为什么不能用 Ansible 或 SaltStack 做这事
Ansible 的 virt 模块底层仍是调 virsh,但它默认串行执行,数千台虚机要数小时;并行开到 -f 100 后,SSH 连接风暴会让控制节点和目标宿主机的 sshd、libvirt 同时过载,出现大量 Connection refused 和 libvirtError: internal error: cannot send data: Broken pipe。
- SaltStack 的
virt.shutdown同样受 libvirt 并发瓶颈制约,且 minion 失联时无法自动降级 - 真实生产中,最稳的是裸
bash + virsh + parallel组合:无中间件、无状态、无长连接,启动快、失败快、可预测 - 曾有客户用 Ansible 跑了 47 分钟才关完 1200 台虚机,改用本地 bash 脚本后压缩到 210 秒(含 90 秒最大等待)
真正难的不是“怎么关”,而是“怎么让每台虚机都在断电前彻底释放磁盘缓存、刷完 journal、卸载 NFS 挂载点”。这取决于虚机内部配置,外部脚本只能尽力触发 shutdown 流程,剩下的得靠虚机自己守规矩。











