什么是 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 争抢