<!DOCTYPE html>
服务器跑着跑着磁盘满了,网站打不开、数据库写入报错、日志疯狂增长——这是运维最头疼的故障之一。好消息是,在绝大多数 Linux 服务器上,磁盘扩容都可以在线完成:不用关机、不用重装系统、数据不丢失。本文从 LVM 逻辑卷扩容、云硬盘热扩容、非 LVM 分区扩容三个场景出发,附上完整的命令实战和常见排错方法,帮你一次搞懂「加磁盘、扩分区、涨文件系统」的全流程。
一、扩容前的准备工作:先看清磁盘现状
动刀之前,先把磁盘现状摸清楚。以下三条命令缺一不可:
# 1. 查看块设备与分区结构
lsblk
# 2. 查看文件系统使用率
df -hT
# 3. 查看分区表(传统 MBR 用 fdisk,GPT 用 gdisk)
fdisk -l /dev/vda
输出示意:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vda 252:0 0 100G 0 disk
├─vda1 252:1 0 1G 0 part /boot
└─vda2 252:2 0 99G 0 part
└─vg-data-lv-data 253:0 0 50G 0 lvm /data
关键点:要区分「磁盘(disk) - 分区(part) - LVM逻辑卷(lv) - 文件系统(fs)」四个层次。扩容是逐层进行的,哪一层没动,最终文件系统就不会变大。先记住判断文件系统类型的命令:
# 查看根分区 / 的文件系统类型
df -T / | awk '{print $2}'
# 常见输出: ext4 或 xfs
重要:ext4 和 xfs 的在线扩容命令完全不同。ext4 用resize2fs,xfs 用xfs_growfs。混用必然报错,后面排错章节会细讲。
二、场景一:LVM 逻辑卷在线扩容(最推荐)
如果当初部署时就用了 LVM(生产环境强烈建议),扩容是最优雅的:PV → VG → LV → 文件系统,四步走,全程无需卸载。
2.1 先确认 PV/VG/LV 现状
pvdisplay # 物理卷,看是否有空闲空间
vgdisplay # 卷组,重点看 VFree 列
lvdisplay # 逻辑卷,看当前大小
2.2 物理层没有空闲空间时,先扩容 PV
云服务器控制台里把系统盘/数据盘扩到 200G 后,磁盘层变大了,但 PV 并不知道。重新扫描 + 扩展 PV:
# 对 KVM 虚拟化(virtio 磁盘),让内核重新读取设备大小
echo 1 > /sys/class/block/vda/device/rescan
lsblk # 确认 vda 已变为 200G
# 把新增的 100G 全部划入现有 PV(注意先 df 确认设备名)
pvresize /dev/vda2
pvdisplay # 确认 PFree 出现空闲空间
2.3 扩容 LV 逻辑卷
# 方式一:增加固定大小
lvextend -L +80G /dev/vg-data/lv-data
# 方式二:扩容到占用 VG 全部剩余空间
lvextend -l +100%FREE /dev/vg-data/lv-data
# 执行后确认
lvdisplay /dev/vg-data/lv-data
2.4 扩容文件系统(关键一步)
# ext4 文件系统:在线扩容
resize2fs /dev/vg-data/lv-data
# xfs 文件系统:必须用 xfs_growfs,且参数是【挂载点】不是设备
xfs_growfs /data
# 验证
df -hT /data
三、场景二:云硬盘热扩容(无 LVM 的裸分区)
很多轻量应用服务器是传统分区(如 /dev/vda1 直接挂根目录),没有 LVM。云厂商控制台扩容磁盘后,需要手动扩分区和文件系统。
3.1 让内核重新识别磁盘大小
# virtio 云盘重扫描
echo 1 > /sys/class/block/vda/device/rescan
# 或执行分区表重读
partprobe /dev/vda
lsblk # 确认磁盘总大小已变化
3.2 用 growpart 扩大分区(GPT/MBR 通吃)
# 把 vda1 分区扩展到磁盘末尾
growpart /dev/vda 1
# 查看分区是否变大
lsblk /dev/vda
若系统没有 growpart(cloud-utils 包),也可以传统方式重建分区表,但起始扇区必须完全一致,否则数据全毁:
# 记录当前分区起始扇区(千万要记下来!)
fdisk -l /dev/vda
# 示例: /dev/vda1 Start=2048
# 进入 fdisk,重建分区(危险操作,务必谨慎)
fdisk /dev/vda
# 按 d 删除分区1,再按 n 新建分区1,Start 填原起始值 2048
# 最后按 w 写入,并执行 partprobe /dev/vda
3.3 扩容文件系统
# 先看类型
df -T /
# ext4
resize2fs /dev/vda1
# xfs
xfs_growfs /
四、场景三:新增一块数据盘(非扩容场景)
如果是新挂载的数据盘,流程是:分区 → 格式化 → 挂载 → 写 fstab,同样不需要重启:
# 1. 查看新磁盘设备名
lsblk -f
# 2. 分区(以 /dev/vdb 为例)
fdisk /dev/vdb
# n → p → 回车两次(默认全盘) → w
# 3. 格式化
mkfs.ext4 /dev/vdb1
# 4. 挂载
mkdir -p /data
mount /dev/vdb1 /data
# 5. 开机自动挂载(先查 UUID)
blkid /dev/vdb1
# 编辑 /etc/fstab 添加一行:
# UUID=xxxx-xxxx /data ext4 defaults,nofail 0 2
# 验证 fstab 语法无误
mount -a
fstab 里强烈建议加 nofail 选项,否则云盘因挂载失败导致开机进不去系统的事故非常常见。
五、常见排错与故障处理
错误 1:resize2fs: Bad magic number in super-block
# 报错示例
resize2fs: Bad magic number in super-block while trying to open /dev/vda1
# 原因:分区是 xfs,你却用了 ext4 的工具
# 解决:改用 xfs_growfs(参数是挂载点)
xfs_growfs /
错误 2:The filesystem is already xxx blocks long. Nothing to do!
# 报错含义:文件系统已经是分区大小了,说明分区本身没变大
# 解决:返回 3.2 步,先 growpart 扩大分区,再扩文件系统
# 排查顺序口诀:磁盘 → 分区 → LVM → 文件系统
lsblk # 看磁盘/分区大小
pvdisplay # 看 PV
lvdisplay # 看 LV
df -hT # 看文件系统
错误 3:Device or resource busy(设备正忙)
# 原因:分区正在被使用,内核未重新读取分区表
partprobe /dev/vda
# 若仍报错,可用 partx 强制刷新
partx -u /dev/vda
# 极端情况下才需要重启;云盘场景建议用 echo 1 > .../rescan 替代
错误 4:xfs_growfs: XFS_IOC_FSGROWFSDATA 失败: No space left on device
# 原因:LV 或分区没有实际变大,xfs 无法扩到期望大小
# 解决:确认 lvextend / growpart 已生效,再执行 xfs_growfs
错误 5:扩容后 df 没变化
# 最常见:文件系统挂在多个挂载点或扩容跑错了设备
# 逐一核对
df -hT
lsblk -f # -f 可以同时显示文件系统类型与 UUID
# 注意:如果 / 是 overlay 或 tmpfs,说明你扩容的是容器/虚拟环境内部
mount | grep -E " / | /data"
六、一键扩容检查脚本
把检查逻辑固化成脚本,扩容前后各跑一遍,避免漏层:
#!/bin/bash
# disk_check.sh - 磁盘扩容检查脚本
echo "===== 磁盘 ====="
lsblk
echo "===== 文件系统 ====="
df -hT | grep -vE "tmpfs|overlay"
echo "===== LVM PV ====="
pvdisplay 2>/dev/null | grep -E "PV Name|Free"
echo "===== LVM LV ====="
lvdisplay 2>/dev/null | grep -E "LV Path|LV Size"
echo "===== 提示 ====="
echo "若磁盘大、分区小:需要 growpart/pvresize"
echo "若分区大、文件系统小:需要 resize2fs/xfs_growfs"
七、总结
磁盘在线扩容的核心是记住「四层检查法」:磁盘 → 分区 → LVM逻辑卷 → 文件系统,每一层都到位,最终 df 才会变大。三个最容易踩的坑:xfs 用错 resize2fs、忘了扩分区直接扩文件系统、fdisk 重建分区时起始扇区抄错导致数据丢失。生产环境建议:部署时就用 LVM 预留弹性;扩容前务必先做快照或备份;每步操作后用 lsblk/df 验证再进下一步。
希望这份指南能帮你少走弯路。如果你在扩容时遇到其他奇葩报错,欢迎在评论区贴出 lsblk 和 df -hT 的输出,我们一起排查。


