☰
KVM虚拟机磁盘空间耗尽故障排查与恢复实战
2026/11/3 15:19:37 网站建设 项目流程

1. 故障现象与初步判断

那天早上刚到办公室,就收到监控系统发来的告警邮件:生产环境中的某台KVM虚拟机突然变成了"paused"状态。登录宿主机查看,确实看到虚拟机状态异常:

# virsh list --all Id Name State ---------------------------------- 3 prod-web-01 paused

这台虚拟机承载着公司官网的业务,必须立即恢复。我首先尝试用virsh resume命令恢复虚拟机:

# virsh resume prod-web-01 error: Failed to resume domain prod-web-01 error: internal error: cannot resume domain: Input/output error

错误信息显示是I/O错误,这提示可能是存储方面的问题。于是立即检查虚拟机日志:

# virsh dumpxml prod-web-01 | grep -i log <log file='/var/log/libvirt/qemu/prod-web-01.log'/> # tail -n 50 /var/log/libvirt/qemu/prod-web-01.log ... 2023-07-15 08:23:45.581+0000: shutting down, reason=failed 2023-07-15 08:23:45.632+0000: cannot write to '/var/lib/libvirt/images/prod-web-01.qcow2': No space left on device

关键线索出现了——"No space left on device"。看来是磁盘空间耗尽导致虚拟机无法正常运行。

2. 宿主机磁盘空间排查

2.1 快速定位问题根源

立即检查宿主机磁盘使用情况:

# df -h Filesystem Size Used Avail Use% Mounted on /dev/sda1 50G 50G 0G 100% / ...

根分区已经100%占满,这正是导致虚拟机I/O错误的直接原因。进一步分析空间占用:

# du -sh /* | sort -rh | head -n 5 25G /var 15G /usr 6.5G /home 3.2G /lib 1.1G /opt

/var目录异常占用了25G空间,这明显不正常。继续深入:

# du -sh /var/* | sort -rh | head -n 5 18G /var/lib 4.2G /var/log 1.3G /var/cache ...

最终定位到是/var/lib/libvirt/images目录下的虚拟机磁盘文件过大:

# ls -lh /var/lib/libvirt/images/ total 18G -rw------- 1 qemu qemu 18G Jul 15 08:20 prod-web-01.qcow2

2.2 空间占用的深层原因

这台虚拟机的磁盘配置原本只有50GB,为什么qcow2文件会膨胀到18GB?通过检查虚拟机配置:

# virsh domblklist prod-web-01 Target Source ----------------------------------------- vda /var/lib/libvirt/images/prod-web-01.qcow2

查看磁盘格式和实际使用情况:

# qemu-img info /var/lib/libvirt/images/prod-web-01.qcow2 image: /var/lib/libvirt/images/prod-web-01.qcow2 file format: qcow2 virtual size: 50 GiB (53687091200 bytes) disk size: 18 GiB cluster_size: 65536 Format specific information: compat: 1.1 lazy refcounts: false refcount bits: 16 corrupt: false

问题出在虚拟机内部的文件系统上。登录虚拟机检查(通过virt-rescue):

# virt-rescue -a /var/lib/libvirt/images/prod-web-01.qcow2 ><rescue> fdisk -l ><rescue> vgscan ><rescue> lvscan

发现虚拟机内部分区使用率确实很高,但更严重的是存在大量被删除但仍被进程占用的文件:

><rescue> lsof | grep deleted nginx 1234 root 5r REG 253,0 4294967296 123456 /var/log/nginx/access.log (deleted) ...

3. 紧急处理与恢复方案

3.1 立即释放磁盘空间

首先需要立即释放宿主机根分区的空间:

  1. 清理系统日志文件:
# journalctl --vacuum-size=200M # rm -f /var/log/*.gz
  1. 删除旧的kernel包:
# package-cleanup --oldkernels --count=1
  1. 清理yum缓存:
# yum clean all
  1. 临时移动大文件(可选):
# mv /var/lib/libvirt/images/prod-web-01.qcow2 /mnt/backup/ # ln -s /mnt/backup/prod-web-01.qcow2 /var/lib/libvirt/images/

3.2 恢复虚拟机运行

释放部分空间后,尝试恢复虚拟机:

# virsh start prod-web-01

如果仍然失败,可以尝试:

  1. 使用qemu-img检查并修复磁盘:
# qemu-img check -r all /var/lib/libvirt/images/prod-web-01.qcow2
  1. 转换磁盘格式释放空间:
# qemu-img convert -O qcow2 /var/lib/libvirt/images/prod-web-01.qcow2 /mnt/backup/prod-web-01-new.qcow2 # mv /mnt/backup/prod-web-01-new.qcow2 /var/lib/libvirt/images/prod-web-01.qcow2

3.3 虚拟机内部清理

成功启动虚拟机后,立即进行内部清理:

  1. 查找并清理大文件:
# find / -xdev -type f -size +100M -exec ls -lh {} \;
  1. 清理日志文件:
# truncate -s 0 /var/log/*.log
  1. 重启占用已删除文件的进程:
# systemctl restart nginx # systemctl restart mysql

4. 根本解决方案与预防措施

4.1 宿主机存储规划最佳实践

  1. 分离存储分区:

    • /var/lib/libvirt/images单独挂载大容量分区
    • 系统分区保持精简
  2. 使用LVM管理存储:

# pvcreate /dev/sdb # vgcreate vg_vm /dev/sdb # lvcreate -L 500G -n lv_vm vg_vm # mkfs.xfs /dev/vg_vm/lv_vm # mount /dev/vg_vm/lv_vm /var/lib/libvirt/images
  1. 设置磁盘空间监控:
# vim /etc/cron.hourly/check_disk #!/bin/bash THRESHOLD=90 df -h | awk '0+$5 >= '$THRESHOLD' {print $6}'

4.2 虚拟机存储配置优化

  1. 启用磁盘空间监控:
<domain> ... <devices> <disk type='file' device='disk'> <driver name='qemu' type='qcow2'/> <source file='/var/lib/libvirt/images/prod-web-01.qcow2'/> <target dev='vda' bus='virtio'/> <iotune> <read_bytes_sec>10000000</read_bytes_sec> <write_bytes_sec>10000000</write_bytes_sec> </iotune> </disk> </devices> </domain>
  1. 使用精简配置(thin provisioning):
# qemu-img create -f qcow2 -o preallocation=metadata prod-web-01.qcow2 50G
  1. 定期压缩磁盘:
# qemu-img convert -O qcow2 -c prod-web-01.qcow2 prod-web-01-compressed.qcow2

4.3 日志管理策略

  1. 配置日志轮转:
# vim /etc/logrotate.d/nginx /var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 www-data adm sharedscripts postrotate [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid` endscript }
  1. 使用日志收集系统:

    • ELK Stack
    • Graylog
    • Loki
  2. 限制日志级别:

# vim /etc/rsyslog.conf *.info;mail.none;authpriv.none;cron.none /var/log/messages

5. 高级排查技巧与工具

5.1 使用libguestfs工具集

  1. 检查虚拟机文件系统:
# virt-df -h prod-web-01
  1. 直接编辑虚拟机文件:
# virt-edit -d prod-web-01 /etc/fstab
  1. 批量清理文件:
# virt-ls -l -R -d prod-web-01 /var/log | grep -i '\.log$'

5.2 KVM高级调试技巧

  1. 启用详细日志:
# virsh dumpxml prod-web-01 > prod-web-01.xml # vim prod-web-01.xml <domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'> ... <qemu:commandline> <qemu:arg value='-d'/> <qemu:arg value='guest_errors'/> </qemu:commandline> </domain> # virsh define prod-web-01.xml
  1. 使用QEMU monitor:
# virsh qemu-monitor-command prod-web-01 --hmp "info block"
  1. 性能监控:
# virt-top

5.3 自动化监控方案

  1. Prometheus监控配置:
# vim /etc/prometheus/prometheus.yml scrape_configs: - job_name: 'libvirt' metrics_path: '/metrics' static_configs: - targets: ['localhost:9177']
  1. Grafana仪表板:

    • 导入Libvirt仪表板ID: 10810
  2. 自定义告警规则:

# vim /etc/prometheus/rules.yml groups: - name: libvirt.rules rules: - alert: HighDiskUsage expr: libvirt_domain_info_disk_usage_bytes / libvirt_domain_info_disk_capacity_bytes > 0.8 for: 5m labels: severity: warning annotations: summary: "High disk usage on {{ $labels.domain }}" description: "Disk usage is {{ $value }}% for {{ $labels.domain }}"

6. 经验总结与避坑指南

6.1 血泪教训

  1. 不要将所有虚拟机存储在系统分区
  2. 定期检查qcow2文件的实际大小与虚拟大小的比例
  3. 注意被删除但仍被进程占用的文件
  4. 日志文件是空间杀手,必须严格管理
  5. 监控系统必须覆盖宿主机磁盘空间指标

6.2 推荐工具链

  1. 空间分析:

    • ncdu
    • baobab
    • du -sh * | sort -h
  2. 虚拟机管理:

    • virt-manager
    • cockpit-machines
    • virsh
  3. 日志管理:

    • logrotate
    • systemd-journald
    • rsyslog

6.3 性能调优参数

  1. I/O调度器设置:
# echo deadline > /sys/block/sda/queue/scheduler
  1. KVM内核参数优化:
# vim /etc/sysctl.conf vm.swappiness = 10 vm.dirty_ratio = 20 vm.dirty_background_ratio = 10
  1. QEMU性能参数:
<cpu mode='host-passthrough' check='none'/> <memoryBacking> <hugepages/> </memoryBacking> <ioThreads>4</ioThreads>

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询