服务器磁盘写满几乎是必然会发生的事:日志在涨、数据库在涨、用户上传的文件在涨,某天早上 df -h 一看使用率 100%,应用开始报错。这时候需要做的就是把磁盘扩起来。如果文件系统是 XFS——RHEL/CentOS/Rocky 系默认、也是很多云主机的默认——扩容方式和 ext4 有一些关键区别,尤其是 XFS 那条"只能扩不能缩"的铁律,决定了你必须一次想清楚、一次做对。
这篇文章按"扩容前的准备 → 云盘扩容 → 分区扩容 → LVM 扩容 → XFS 在线扩容 → 校验"的顺序,把整套流程讲清楚,并特别说明哪些步骤是真实在线、哪些步骤需要卸载文件系统、哪些操作一旦做错会造成数据损坏。读完你应该能独立完成一次 XFS 在线扩容,并且知道每一步之后该用什么命令确认自己没做错。
需要强调的核心前提:XFS 支持在线扩容(文件系统处于挂载状态也能扩),但完全不支持缩容。 这个不对称性意味着扩容是相对安全的操作,而"扩多了想收回来"几乎不可能。所以本文的重点不是"怎么扩",而是"怎么按正确顺序扩、扩完怎么验证"。
一、扩容前必须先搞清楚的三件事
动手前,把下面三个问题回答清楚,能避免绝大多数事故。
第一,当前容量结构是什么? 是"裸盘直接格式化",还是"LVM 逻辑卷",还是"云盘 + 分区 + 文件系统"三层?三者扩容步骤完全不同。用下面的命令一次看全:
# 看块设备树,能直观看到 磁盘 → 分区 → LVM 的层级关系
lsblk
# 看文件系统类型、容量、挂载点
df -Th
# 看 LVM 情况(如果有)
sudo pvs # 物理卷
sudo vgs # 卷组
sudo lvs # 逻辑卷
# 看 XFS 文件系统详细信息
xfs_info /data
第二,剩余空间在哪里? 扩容的本质是"把空闲空间喂给文件系统"。空闲空间可能来自三种地方:云盘本身还没分配的空间(扩容云盘后出现)、卷组里还没分配的空闲 PE、或者同一卷组里其他逻辑卷腾出来的空间。
第三,能不能停服? 裸分区扩容(不重启识别新容量)通常无法在线完成,需要卸载文件系统甚至重启;LVM 扩容可以做到全程在线。这决定了你能不能在业务高峰期操作。
把三种常见容量结构及其对应的扩容路径整理成一张表,动手前先对号入座:
| 当前结构 | 典型形态 | 是否需要重启 | 扩容步骤 | 在线可行性 |
|---|---|---|---|---|
| 裸分区 + XFS | /dev/vdb1 → /data |
视内核能否热重读分区表 | growpart → xfs_growfs |
多数可在线 |
| LVM + XFS | PV → VG → LV → /data |
否 | growpart → pvresize → lvextend → xfs_growfs |
可全程在线 |
| 卷组空间不足 | 需要新增 PV | 否 | 新增盘 → pvcreate → vgextend → lvextend → xfs_growfs |
可全程在线,需加盘 |
根分区 / 是 XFS |
/dev/vda2 或 /dev/mapper/vg-root |
通常否 | 扩分区/LV → xfs_growfs / |
可在线,但风险最高 |
对号入座之后,按下面的顺序执行即可。无论哪种情况,最底层的那一步(扩分区或扩 LV)永远在文件系统之前。
二、云盘扩容:先让操作系统看到更大的盘
如果你用的是云服务器,第一步是在云控制台把云盘的容量调大(比如从 100 GB 调到 200 GB)。这一步做完之后,操作系统里 df -h 是不会有任何变化的,因为文件系统还没动,甚至连分区表都还没更新。这是新手最容易困惑的地方。
先从内核层面确认新容量已经被识别:
# 查看磁盘实际容量,对比扩容前后的数值
lsblk
sudo fdisk -l /dev/vdb
# 如果 lsblk 显示的容量还是旧的,触发内核重新读取分区表
sudo partprobe /dev/vdb
# 或者(SCSI 设备)
echo 1 | sudo tee /sys/class/block/vdb/device/rescan
# 少数云厂商的云盘需要重启才能识别
sudo reboot
三、情况一:裸分区 + XFS(无 LVM)
假设 /dev/vdb1 直接格式化为 XFS 挂在 /data,扩容前 100 GB,云盘已扩到 200 GB。这种情况下有两种做法。
做法 A:不删除分区,直接扩分区(推荐,growpart 是云厂商镜像常带的工具):
# RHEL/CentOS/Rocky:安装 cloud-utils-growpart
sudo yum install -y cloud-utils-growpart
# Debian/Ubuntu:
sudo apt update && sudo apt install -y cloud-guest-utils
# 把分区 1 扩到磁盘最大(注意:磁盘和分区号之间用空格)
sudo growpart /dev/vdb 1
# 分区表更新后,再扩 XFS 文件系统
sudo xfs_growfs /data
# 验证
df -h /data
做法 B:用 parted 手动调整分区终点:
sudo parted /dev/vdb
# 进入交互后:
# (parted) print # 查看分区,记下分区 1 的起始扇区
# (parted) resizepart 1 # 选择扩分区 1
# End? [100GB]? 200GB # 输入新的终点
# (parted) quit
sudo partprobe /dev/vdb
sudo xfs_growfs /data
关键点:growpart 和 parted resizepart 只改分区表,不动文件系统;xfs_growfs 只扩文件系统,不动分区表。两步必须都做,先分区后文件系统,顺序不能反。 分区没扩,xfs_growfs 就无从扩起。
四、情况二:LVM + XFS(推荐架构)
LVM 是扩容体验最好的方案,可以做到完全在线。假设结构是:/dev/vdb → vdb1(PV)→ 卷组 vgdata → 逻辑卷 lvdata → XFS 挂在 /data。
标准三步走:
# 第一步:让 PV 认识扩容后的分区(前提是分区已经扩了,方法同上)
sudo growpart /dev/vdb 1
sudo pvresize /dev/vdb1
# 第二步:从卷组里给逻辑卷加空间。+50G 表示在现有基础上加 50G
# 也可以写 -l +100%FREE 表示把剩余空间全给这个 LV
sudo lvextend -L +50G /dev/vgdata/lvdata
# 或
sudo lvextend -l +100%FREE /dev/vgdata/lvdata
# 第三步:扩 XFS 文件系统
sudo xfs_growfs /data
# 一条命令搞定"扩 LV + 扩文件系统"(-r 表示同时 resize 文件系统)
sudo lvextend -r -L +50G /dev/vgdata/lvdata
# 验证
sudo lvs
df -h /data
如果卷组本身空间不够,还要先加 PV:新插一块盘或新增一个云盘,然后 pvcreate /dev/vdc1 && vgextend vgdata /dev/vdc1,再执行 lvextend。
五、极特殊情况:/ 根分区是 XFS 需要扩容
根分区扩容稍微麻烦一点,但 XFS 依然支持在线 xfs_growfs(根分区本身就是挂载状态):
# 先确认根分区所在设备
findmnt -n -o SOURCE /
df -Th /
# 若是 LVM,直接扩 LV 并在线扩文件系统
sudo lvextend -r -L +20G /dev/mapper/vg00-root
# 若是裸分区,先扩分区,再扩文件系统
sudo growpart /dev/vda 2
sudo xfs_growfs /
风险提示:
growpart、parted resizepart、lvextend、xfs_growfs都是不可逆的写操作。虽然扩容本身丢数据的风险不高,但操作对象写错设备名(比如把数据盘写成系统盘)会造成分区表损坏、系统无法启动。执行growpart、parted前务必用lsblk再确认一次设备名和分区号;生产环境先做云盘快照。回滚方式:lvextend可以lvreduce(但 XFS 不能缩,所以对 XFS 无实际回滚意义);分区表变更只能靠备份恢复,没有可靠的原地回滚手段。
六、扩容后的完整校验清单
扩容完不要只看一眼 df -h 就结束,按下面逐项确认:
# 1. 容量是否到位
df -h /data
lsblk /dev/vdb
# 2. 文件系统是否健康(无错误、无 corruption)
sudo xfs_repair -n /dev/vgdata/lvdata # -n 只检查不修改,安全
# 3. 挂载参数是否正常
findmnt /data
# 4. 实际写测试:写一个已知大小的文件确认能写满新空间
dd if=/dev/zero of=/data/testfile bs=1M count=1024 oflag=direct
ls -lh /data/testfile
rm -f /data/testfile
# 5. 看 dmesg 有没有 XFS 相关的告警
sudo dmesg | tail -30 | grep -i xfs
xfs_repair -n 只做只读检查,不会改动数据,可以在挂载状态下跑(但完整检查建议卸载后做,且只能在文件系统卸载后执行修复,挂载状态跑 xfs_repair 不带 -n 会被拒绝)。这一步是确认扩容没搞坏元数据的重要手段。
七、扩容耗时的量级参考
很多人在动手前会担心"扩容是不是要跑很久、业务会不会卡住"。这里给几个经验值帮助判断:
- LVM 扩逻辑卷本身(
lvextend)是元数据操作,通常在毫秒到秒级完成,几乎不产生 I/O 压力。 xfs_growfs扩大文件系统也属于元数据操作,它只更新空闲空间管理结构,不搬运已有数据,因此几秒内就能完成,即使文件系统已经装了上 TB 数据也一样快。这与很多人的直觉相反:扩容不迁移数据,所以不慢。- 真正慢的是"创建文件系统"和"全盘扫描修复"(
xfs_repair),它们才需要按数据量线性耗时。扩容流程里没有这两个动作。
因此,在 LVM + XFS 的架构下,扩容是一个对业务几乎无感知的操作,可以安排在业务时段进行,不必刻意等到凌晨。反过来,如果某次 xfs_growfs 跑了很久甚至卡住,往往说明底层存储(云盘后端、RAID 卡)响应变慢,值得排查而不是干等。
另外要注意顺序上的一个细节:分区表的更新(growpart/parted)有时需要内核重新读取分区表才生效。如果 growpart 执行后 lsblk 显示的分区大小没变,执行一次 partprobe /dev/vdb 通常即可;个别老内核不支持热重读,就只能安排一次重启。这也是"能否全程在线"的唯一变数,与 XFS 本身无关。
八、XFS 扩容的常见误区
误区一:xfs_growfs 需要停机。 不需要,这是它最大的优势,文件系统挂载状态下就能扩。
误区二:df 不变就是扩容失败。 先检查是不是只做了分区没做文件系统,或者反过来。分区和文件系统是两层,两层都要扩。
误区三:XFS 能缩容。 不能。这是硬限制,别信网上的偏方。如果确实要缩小,只能备份、重建、恢复。
误区四:把 xfs_growfs 的参数写成设备名。 xfs_growfs 的参数是挂载点(如 /data),不是设备名(如 /dev/vdb1)。写成设备名会报错。而 xfs_repair 的参数恰恰是设备名。这两个命令的参数习惯相反,容易搞混。
误区五:扩容后忘了扩云盘本身。 有些人在 LVM 层折腾半天,忘了云控制台那一步,结果卷组根本没空间可用。
常见问题
Q1:XFS 扩容会影响业务吗?
LVM + XFS 的在线扩容几乎无感知,通常毫秒级完成。裸分区扩容如果不需要重启,也基本无影响;如果需要重启识别容量,则有分钟级中断。
Q2:扩容之后 df 显示的数字比预期少,为什么?
一种可能是只扩了分区、没扩文件系统;另一种是 XFS 需要预留部分元数据空间,或者文件系统在创建时未占满分区,所以可用空间略小于设备容量。用 xfs_info /data 看 data 段的块数和 df -h 对比。
Q3:云盘扩了但 lsblk 还是旧容量怎么办?
先 partprobe /dev/vdb,不行就 echo 1 > /sys/class/block/vdb/device/rescan,再不行只能重启。少数虚拟化平台需要关机后调整。
Q4:能把一个 XFS 文件系统迁移到更大的盘上吗?
可以,用 xfs_copy 或 xfsdump/xfsrestore,把数据迁到新盘的新 XFS 上。注意 xfs_copy 要求目标不小于源。
Q5:lvextend -r 和分两步做有区别吗?
-r 只是把"扩 LV + 扩文件系统"合并成一步,底层一样,但更不容易漏掉第二步。推荐用 -r。
总结
- XFS 扩容的核心是"两层都要扩":先扩分区/逻辑卷(块设备层),再
xfs_growfs扩文件系统。 - LVM + XFS 是扩容体验最好的组合,全程在线,推荐新盘就按这个架构规划。
- XFS 只能扩、不能缩,规划容量时宁可按需逐步扩,也不要一次给太大。
- 云服务器扩容第一步永远是在控制台调大云盘,然后才是分区和文件系统。
- 每次扩容后用
xfs_repair -n+dd写测试 +dmesg三项确认,比只看df靠谱得多。 - 所有操作前用
lsblk二次确认设备名,并保留快照,这是不可逆操作的最后保险。
企业QQ咨询




