什么是 io-error
当 PVE 虚拟机的存储后端出现 I/O 故障时,QEMU 会将虚拟机置于 io-error 暂停状态。此时虚拟机并未关机,而是冻结在故障发生的瞬间,等待管理员介入。
在 Web 界面上表现为虚拟机状态显示为 paused,通过 QMP 接口查询则会明确返回 io-error。
常见原因
| 原因 | 说明 |
|---|---|
| 存储空间不足 | LVM thin pool、Ceph pool 或 NFS/ZFS 存储空间耗尽 |
| 存储后端故障 | Ceph OSD 掉线、NFS 挂载断开、iSCSI 连接超时 |
| 磁盘 I/O 超时 | 底层物理磁盘故障或 RAID 降级导致响应超时 |
| 快照/备份冲突 | 备份任务占用锁或快照链损坏 |
| 网络存储抖动 | 使用网络存储时网络中断或延迟过高 |
排查步骤
1. 检查存储状态
1# 查看存储使用情况
2pvesm status
3
4# 查看 LVM thin pool 使用率
5lvs
6
7# 如果是 Ceph
8ceph -s
9ceph osd tree
2. 查看系统日志
1# 查看内核 I/O 错误
2dmesg | grep -i "error\|timeout\|reset"
3
4# 查看 PVE 任务日志
5journalctl -u pvedaemon --since "1 hour ago"
3. 确认虚拟机 QMP 状态
1pvesh get /nodes/$(hostname)/qemu/VMID/status/current --output-format json | jq .qmpstatus
修复方法
在确认存储后端已恢复正常后,执行 qm resume VMID 即可恢复虚拟机运行。
如果虚拟机较多,手动逐个检查效率较低,可以使用以下脚本自动巡检并恢复。
自动修复脚本
1#!/bin/bash
2# pve-fix-io-error.sh
3# 扫描所有虚拟机,自动恢复处于 io-error 状态的 VM
4
5set -euo pipefail
6
7NODE=$(hostname)
8LOG_FILE="/var/log/pve-io-error-fix.log"
9RETRY_WAIT=2
10FOUND=0
11
12log() {
13 local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $1"
14 echo "$msg"
15 echo "$msg" >> "$LOG_FILE"
16}
17
18log "开始扫描 io-error 状态的虚拟机..."
19
20# 获取所有 VMID
21mapfile -t VMIDS < <(qm list 2>/dev/null | awk 'NR>1 {print $1}')
22
23if [[ ${#VMIDS[@]} -eq 0 ]]; then
24 log "未发现任何虚拟机,退出。"
25 exit 0
26fi
27
28for vmid in "${VMIDS[@]}"; do
29 # 通过 jq 解析 QMP 状态,比 grep+cut 更可靠
30 qmp_status=$(pvesh get "/nodes/$NODE/qemu/$vmid/status/current" --output-format json 2>/dev/null | jq -r '.qmpstatus // empty')
31
32 if [[ "$qmp_status" != "io-error" ]]; then
33 continue
34 fi
35
36 FOUND=$((FOUND + 1))
37 log "[!] VM $vmid 处于 io-error 状态"
38
39 # 尝试恢复
40 if qm resume "$vmid" 2>>"$LOG_FILE"; then
41 sleep "$RETRY_WAIT"
42 new_status=$(pvesh get "/nodes/$NODE/qemu/$vmid/status/current" --output-format json 2>/dev/null | jq -r '.status // empty')
43
44 if [[ "$new_status" == "running" ]]; then
45 log "[OK] VM $vmid 已恢复运行"
46 else
47 log "[FAIL] VM $vmid 恢复失败 (当前状态: $new_status),请检查存储后端"
48 fi
49 else
50 log "[FAIL] VM $vmid resume 命令执行失败"
51 fi
52done
53
54if [[ $FOUND -eq 0 ]]; then
55 log "所有虚拟机状态正常,未发现 io-error。"
56else
57 log "共处理 $FOUND 台 io-error 虚拟机。"
58fi
部署定时巡检
将脚本保存并设置 cron 定时执行:
1# 保存脚本
2cp pve-fix-io-error.sh /usr/local/bin/pve-fix-io-error.sh
3chmod +x /usr/local/bin/pve-fix-io-error.sh
4
5# 每 5 分钟巡检一次
6crontab -e
添加以下内容:
1*/5 * * * * /usr/local/bin/pve-fix-io-error.sh
日志输出到 /var/log/pve-io-error-fix.log,可随时查看历史修复记录。
预防建议
- 存储使用率超过 80% 时及时扩容或清理
- 对 Ceph/NFS 等网络存储配置监控告警
- 定期检查磁盘 SMART 状态:
smartctl -a /dev/sdX - 备份任务错开高峰期执行,避免 I/O 争抢