上个月收到监控告警,说根分区使用率 92%。
登录上去 df -h 一看,四十个 G 的盘只剩三个多 G。du -sh /* 挨个看,/var/lib/docker 占了大头,还有一堆构建缓存。
清了一轮,回到 60%。但我知道这只是暂时的,服务还在长,早晚得扩。
还好当初装系统的时候选了 LVM。要是普通分区,扩容就得停机、进救援模式、用 fdisk 调分区,风险大得多。
先理清楚 LVM 的三层
很多人被 LVM 绕晕,是因为它的名字太多。其实就三层。
物理层是 PV,Physical Volume,一块硬盘或者一个分区,初始化之后交给 LVM 管。
中间层是 VG,Volume Group,一个池子,把多个 PV 合成一个大的存储空间。
上层是 LV,Logical Volume,从池子里划出来的一块,格式化之后挂载使用。
扩容的时候,顺序是从下往上。先让 PV 变大,VG 才会跟着变大,然后才能扩 LV,最后扩文件系统。
搞反了就白做。
看现在的状态
|
|
输出大概是这样:
|
|
这块盘 40G,vda3 是 LVM 的物理分区,占了 39.5G。里面划了三个 LV。
问题是我这块盘本来就只有 40G,没有剩余空间。所以要扩,得先给虚拟机加盘。
加盘
在云控制台或者虚拟化平台里,把磁盘从 40G 调到 80G。这一步在云厂商那边点一下就行,不用停机。
加完之后,虚拟机里 lsblk 还是显示 40G,因为内核还没重新读分区表。
|
|
这就是关键的一步。vda 本身变大了,但 vda3 这个分区没变。
扩分区
有两种情况。
如果你用的是 GPT 分区表,而且分区后面没有别的分区,用 growpart 最省事:
|
|
growpart 是 cloud-utils-growpart 包里的工具,大部分云镜像都预装了。
如果没装,apt install cloud-utils-growpart 或者 yum install cloud-utils-growpart。
跑完再看:
|
|
vda3 应该变成 79.5G 了。
如果是 MBR 分区表,growpart 也能处理,但有个限制,主分区最多四个,而且扩展分区后面的空间不好扩。这种情况下得用 fdisk 删了重建分区,fdisk 的 d 删分区只删分区表项,不动数据,只要起始扇区没变就是安全的。不过操作的时候手要稳。
让 PV 认识新的大小
分区变大了,但 LVM 还不知道。因为 PV 里记录了自己的大小。
|
|
这个命令会让 PV 重新读取分区的大小,然后更新自己的元数据。
验证:
|
|
输出里的 PSize 应该变成 79.5G,PFree 是新增的空间。
如果 PFree 没变,说明 pvresize 没生效,回头检查分区是不是真的扩了。
扩 LV
|
|
看当前的 LV 大小。
扩的时候有两种写法。
按绝对值扩到某个大小:
|
|
注意 -L 是最终大小,不是增量。如果你写 -L 40G 而当前已经是 40G,它什么都不会做。
按增量扩:
|
|
这个更直观,加二十个 G。
或者干脆把池子里的空间全用掉:
|
|
注意这里是小写的 -l,后面跟百分比。大写的 -L 后面跟具体数值。这个大小写很容易看错。
扩文件系统
这一步最容易被忘。LV 变大了,但上面的文件系统还是原来的大小,df -h 看不出变化。
ext4 用:
|
|
不用给大小,它会自动扩到 LV 的边界。
xfs 用:
|
|
注意 xfs 的 xfs_growfs 参数是挂载点,不是设备名。写 /dev/vg0/root 会报错。
这是两个文件系统最明显的区别。ext4 可以缩,xfs 只能扩。所以如果你的盘用 xfs,规划的时候要留点余量,缩不回去。
在线扩容
好消息是,上面这些操作除了 growpart 之外,全都可以在线做,不用卸载不用停机。
ext4 从内核 3.6 开始支持在线扩容,resize2fs 会自动检测并走在线模式。xfs 一直是在线的。
我用的是 ext4,整个流程在跑着服务的机器上做完,中间没有中断。nginx 和数据库都没感觉。
不过还是建议在业务低峰做。虽然理论上是安全的,但万一 growpart 把分区表写坏了,那就是大事故。
一次完整的操作
把上面的命令串起来,加上 df 前后的对比:
|
|
我实际跑的时候,每一步之间都 lsblk 或 pvs 确认一下。多敲几条命令,比出问题再回头找强。
几个坑
growpart 之后忘了 pvresize,这是最常见的。pvs 里 PFree 是 0,你就会以为是分区没扩成功,其实只是 LVM 不知道。
lvextend 用了 -L 但写的是增量值,比如 -L 20G 而当前已经是 20G,它什么都不做,也不报错。
xfs 用 resize2fs 会直接报错说不支持,别慌,换 xfs_growfs。
还有一个,如果你的 /boot 在 LVM 上,扩它是可以的,但 grub 那边可能需要重新生成配置。我这个机器的 /boot 是独立分区,没在 LVM 里,所以没遇到。
缩容的注意事项
扩容易,缩难。
ext4 缩容要三步。先 umount,然后 e2fsck -f 检查,再 resize2fs <设备> <目标大小>,最后 lvreduce。
顺序不能反。先缩文件系统再缩 LV。如果先缩 LV,文件系统就损坏了,数据基本找不回来。
xfs 根本不支持缩容。要用 xfs 又想缩,只能备份、重建、恢复。
所以我的建议是,宁可一开始规划得保守一点,也不要给自己留缩容的活。
磁盘规划的一点经验
装系统的时候我习惯这么分:
/boot 给 512M,独立分区,不在 LVM 里。这是为了让 grub 和系统救援都能正常工作。
swap 给内存的一到两倍,但不超过 4G。现在很多云厂商建议不给 swap,我的看法是留一点,防止突发的内存尖峰直接把进程打死。
/ 给剩下的全部。不用单独分 /var 和 /home,因为 LVM 的好处就是可以动态调,一开始分太细反而失去了灵活性。
这样分下来,如果哪天 /var/lib/docker 涨得太快,我直接扩根分区就行,不用去动别的。
现在的状态
扩到 80G 之后,根分区用了 38%,/data 那边还有空间。跑了一个多月,稳定。
顺手做了两件事。一是给 docker 加了 data-root 的迁移,把镜像目录挪到了 /data 下面,这样系统盘的压力小很多。二是加了个监控,磁盘到 85% 就推消息,不用等到 92% 才被叫醒。
LVM 这个东西,平时感觉不到它的存在,真正需要的时候才发现它的好。当初装系统多勾了一个选项,省了今天一晚上的事。