磁盘告警在凌晨三点响起来的时候,没有哪个运维是不崩溃的。连续两周,某台线上服务器的 /data 分区使用率一路上涨,日志轮转、临时文件、数据库归档全往里面堆,眼看就要顶到 100%。当时最尴尬的是:这块盘当初直接整盘格式化后挂载,压根没做 LVM,想扩容只能先卸载、再改分区、重建文件系统,一个操作失误数据就没了。
Linux 磁盘管理绕不开的就四件事:分区、格式化、挂载,以及用来规避上述痛苦场景的 LVM。这篇文章把自己这些年实际踩过的坑、用顺手的命令、还有每次都要反复确认的细节完整串一遍,从磁盘识别一直讲到 LVM 在线扩容。适合刚接手服务器运维的开发者,也适合已经会分区但想系统梳理挂载和 LVM 流程的朋友。
1. 先看清家底:磁盘识别与分区策略
1.1 动手前必查的三个命令:lsblk、fdisk -l、blkid
我在任何磁盘操作之前都要花两分钟把机器状态摸一遍,顺序基本固定。先执行lsblk,这个命令会把所有块设备按树状结构打出来,一眼就能看出哪块盘有多大、有没有挂载、分区长什么样。输出里的sda、sdb是传统 SCSI/SATA 设备的命名,nvme0n1是 NVMe 固态盘,它的分区会显示成nvme0n1p1、nvme0n1p2,这个细节在写自动化脚本时特别容易翻车。
接着用fdisk -l或parted -l看物理盘的详细参数,重点是两个信息:磁盘总容量和分区表类型。fdisk -l输出底部会显示Disk /dev/sdb:2.7 TiB之类的总容量,这是规划分区方案的依据。再配合blkid,它能输出每个分区的 UUID 和文件系统类型。UUID 这个字段请务必记住,后面写/etc/fstab的时候全靠它来精确识别设备。
这三个命令各管一段:lsblk看结构,fdisk -l看容量,blkid看身份。信息凑齐了,再做任何分区或格式化动作心里都有底。
1.2 分区表选型:为什么新盘一律 GPT
老机器上经常看到 MBR 分区表,新服务器基本全是 GPT。MBR 有两条硬限制:单块磁盘最大约 2TB,最多只能划 4 个主分区。想绕开主分区数量限制还得用扩展分区和逻辑分区的嵌套方案,操作繁琐且不稳。GPT 没有这两个约束,单盘容量上限大得多,分区数量也灵活,对现在动辄几 TB 的服务器硬盘来说没有理由不用 GPT。
实际操作的差异也很明显:fdisk默认在 MBR 分区表上工作,parted更擅长处理 GPT。用 parted 创建 GPT 分区表的命令通常是parted -s /dev/sdb mklabel gpt。注意,这个动作会清空磁盘上已有的分区表结构,执行前务必确认盘符没有写错。我见过有人在多盘机器上把sdc敲成sdd,一条命令下去整块盘变空白,所以mklabel这种危险操作一定要放在新手也能一眼看出来的位置上,比如单独一行注释写明"以下操作会清空磁盘"。
1.3 分区策略:给未来留后路比一次性分满更重要
很多朋友装完系统就撒手不管,根分区一整块,数据分区一整块,等用了一年半载发现根分区不够用,才开始后悔当初没有规划。这里分享我自己坚持的一套思路:/boot 独立分区,容量给 500M 到 1G 就够;根分区单独划,别和 /home 挤在一起;数据盘不要直接裸盘格式化,全部引导进 LVM 再做逻辑卷切割。
举个例子,一台标配的 512G SSD 系统盘加 2T HDD 数据盘的服务器,我的分区方案大致是:
| 挂载点 | 来源 | 容量 | 文件系统 |
|---|---|---|---|
| /boot | 系统盘独立分区 | 1G | xfs |
| / | 系统盘 LVM 逻辑卷 | 200G | xfs |
| /home | 系统盘 LVM 逻辑卷 | 剩余全部 | xfs |
| /data | 数据盘 LVM 逻辑卷 | 按需切割 | xfs |
这套方案的好处很直白:逻辑卷随时可以在线扩,而普通分区想扩就得动分区表。数据盘先丢进 LVM 的卷组,再按业务需要切逻辑卷,后续空间不够只需lvextend一条命令,完全不用停机。
2. 格式化不是 mkfs 一把梭:文件系统选型与参数细节
2.1 文件系统三选一:ext4、xfs 还是 btrfs
格式化之前先选文件系统,这是整个流程里最容易被随手带过的环节,但选错后面很难受。
ext4 是 Linux 生态里最老牌、兼容性最优的文件系统,CentOS 7 之前的系统盘基本都是它。它有个 xfs 不具备的好处:支持缩容,虽然缩容操作需要卸载分区、有风险,但至少给了退路。xfs 是 RHEL 系现在的默认选择,高并发写入性能好,对超大文件的支撑更稳,硬伤是不能缩容,只能扩不能缩。btrfs 功能丰富,有写时复制、子卷、快照,但调试复杂度偏高,不太建议新手直接在生产环境主力使用,出问题时排查链路更长。
| 文件系统 | 系统盘推荐度 | 在线扩容 | 缩容 | 适合场景 |
|---|---|---|---|---|
| ext4 | 高 | 支持 | 可,但需卸载 | 系统盘、通用数据盘 |
| xfs | 高 | 支持 | 不支持 | 大数据文件、日志存储 |
| btrfs | 中 | 支持 | 支持 | 需要高级特性的场景 |
我现在的习惯是:系统盘用 xfs,因为 RHEL 系的默认一致性检查工具对 xfs 支持得最完整;数据盘如果明确知道以后要搬家或裁剪,就选 ext4;日志、归档这类只增不减的数据放 xfs 非常舒服。
2.2 mkfs 参数里的坑:-m 预留和 -f 强制的含义
选好文件系统后进入实际操作,最常见的写法是:
sudo mkfs.xfs -f /dev/sdb1 sudo mkfs.ext4 -m 1 /dev/sdb1mkfs.ext4的-m参数默认值是 5,意思是给 root 用户预留 5% 的块。1TB 的数据盘,5% 就是凭空少了 50GB 可用空间,这个比例对大数据分区太高了。我会在数据盘上把-m降到 1,系统盘保留默认 5% 也没问题。
mkfs.xfs的-f参数表示强制覆写。目标分区上没有旧文件系统时,不加-f也能顺利格式化;如果设备上已有数据,系统会自动拦截。这个拦截机制其实是保护,我一般不建议随手加-f,确认无误再覆写也不迟。
2.3 格式化命令的安全底线:确认三次再动手
任何mkfs操作之前,我都要求自己按固定顺序跑三遍检查:先lsblk看盘符,再blkid看是否已有数据,最后df -hT看该盘是否已挂载到线上目录。三遍检查都通过才执行格式化。代价只是一分钟,但能避免"想格式化 sdd 却敲成 sdb"这种灾难。如果盘上已有数据且确定要清空,我会先把备份状态写到旁边,确认备份的备份已经落地,再继续。
3. 挂载与开机自启:fstab 的正确打开方式
3.1 mount 的日常用法与高频选项
格式化完成后,需要把分区挂载到某个目录才能使用。临时挂载很简单:
sudo mkdir -p /data sudo mount /dev/sdb1 /datamount有几个高频选项值得注意。defaults其实是 rw、suid、dev、exec、auto、nouser、async 的组合,大多数场景直接用它即可。生产环境我一般会额外加上noatime,意思是访问文件时不更新访问时间戳。这个选项在高并发读场景下能明显降低 IO 压力,因为默认情况下每次读取文件都要写一次元数据,对机械盘性能影响特别明显。
卸载用umount /data,但常遇到"目标忙"的提示,说明有进程还在占用这个挂载点。先用lsof +D /data或fuser -mv /data找出占用进程,处理完再卸载。直接用umount -l强制卸载虽然方便,但会让进程访问到半挂载状态的文件系统,存在数据写入异常的风险,我不建议拿来应应急。
3.2 fstab 六列字段拆解:为什么首选 UUID
临时挂载重启就失效了,开机自动挂载必须写进/etc/fstab。fstab 的每一行分六列,顺序不能乱:
设备标识 挂载点 文件系统类型 挂载选项 dump备份 fsck检查优先级
用一个实际例子说明:
UUID=2a8b3c9e-1f2a-4c9d-8a7b-6e5d4f3a2b1c /data xfs defaults,noatime 0 0第一列我永远选 UUID 而不是/dev/sdb1。原因很现实:Linux 内核在启动时对设备名的分配并不保证固定,插拔、驱动加载顺序都可能让 sdb 变成 sdc。用 UUID 则保证这个分区的身份恒定,不会因为盘符漂移而挂错盘。获取 UUID 用blkid /dev/sdb1。
第二列是挂载点,第三列是文件系统类型,第四列是挂载选项,第五列是 dump 备份标记,一般填 0,第六列是 fsck 检查优先级:根分区填 1,其他填 2 或 0。fstab 写完后先执行mount -a测试,没有报错再重启。这个习惯能筛掉大部分低级错误,因为mount -a会尝试挂载所有 fstab 中未挂载的条目,一旦有字段写错会立刻报错。
3.3 fstab 写错导致系统起不来:应急修复链路
很典型的场景:fstab 里的 UUID 敲错一位,重启后系统直接进入救援模式,报"文件系统无法挂载"。遇到这种情况千万别慌,输入 root 密码进入单用户模式,依次执行:
mount -o remount,rw / vim /etc/fstab把错误行修正,重启即可。如果确实不知道那行 UUID 对应的设备,先用blkid对比系统里实际存在的 UUID。如果机器本身没有 root 密码,就只能走引导盘的救援环境了。运维事故处理里,fstab 写错引发的启动失败占了很大比例,救回来之后一定要反问自己:编辑 fstab 时是不是没做mount -a预检。
4. LVM 实战:从部署到在线扩容的完整链路
4.1 三个抽象层:PV、VG、LV 到底各管什么
LVM,全称 Logical Volume Manager,把传统磁盘映射成三个抽象层:物理卷 PV、卷组 VG、逻辑卷 LV。可以这样理解:PV 是原材料,对应整块磁盘或分区;VG 是仓库,把多份原材料混在一起统一管理;LV 是从仓库里切出来的一块空间,直接挂载给文件系统使用。
整套体系的价值在于:传统分区扩容通常要动分区表,而 LVM 让"加一块新磁盘进仓库,再从仓库里扩逻辑卷"变成一串可以在线完成的命令,业务不停、数据不丢。它的模型有点像公寓里的公摊面积:你不关心管道具体从哪个房间走,只看最终分到手的实用面积够不够,缺了再往公摊里加房间就行。
4.2 从分区到逻辑卷的完整命令流
先用 parted 或 fdisk 把整块盘建一个 LVM 分区。以 /dev/sdb 为例,新建分区时类型标记为 Linux LVM,fdisk 里是t子命令,代码8e;parted 里则是设置lvm标志。
sudo pvcreate /dev/sdb1 sudo vgcreate vg_data /dev/sdb1 sudo lvcreate -L 100G -n lv_data vg_data sudo mkfs.xfs /dev/vg_data/lv_data sudo mkdir -p /data sudo mount /dev/vg_data/lv_data /data这一步做完,/data 上就是一个 100G 的逻辑卷了,后续扩容完全不用碰分区表。日常查看状态用pvs、vgs、lvs三个命令,分别对应三层结构,信息一目了然。养成习惯,扩容前先vgs确认卷组剩余空间,避免lvextend时才发现空间不够。
4.3 在线扩容真实场景:加盘、扩卷、文件系统一步不落
场景重现:/data 的 100G 满了,我加了一块 200G 的新磁盘 /dev/sdc。整个过程全程在线,业务不用停:
sudo pvcreate /dev/sdc sudo vgextend vg_data /dev/sdc sudo lvextend -L +100G /dev/vg_data/lv_data注意最后还差一步。lvextend只是把 LV 的容量扩大了,文件系统并不知道。ext4 要跑resize2fs,xfs 要跑xfs_growfs,而且这两个命令都是在挂载状态下直接执行的,不需要卸载:
sudo xfs_growfs /data执行完df -h就能看到容量生效。这里最常见的坑是只执行了lvextend忘了扩文件系统,导致df里的容量纹丝不动,下面踩坑部分会详细展开。
4.4 缩容与快照:能不做就不做,但要会做
LVM 支持缩容,但限制很多。xfs 明文规定不支持缩容;ext4 虽然支持,但必须先卸载分区、依次执行resize2fs缩小文件系统、lvreduce缩小逻辑卷,再挂载回去。任何一步顺序错了都可能把文件系统搞坏。我的态度是:缩容当作备选方案而不是常规操作,真正需要缩容时靠迁移数据、重建文件系统来解决,比提心吊胆地缩卷稳得多。
LVM 还有一个被低估的功能是快照。lvcreate -s可以对逻辑卷做写时复制快照,在做重要变更前打一个,万一操作失误可以快速回滚。比如升级数据库前先建快照:
sudo lvcreate -L 5G -s -n lv_data_snap /dev/vg_data/lv_data快照会占用卷组里的真实空间,所以别建完就忘,用完及时lvremove清理。
5. 踩坑实录:那些让我"通宵"的磁盘事故
5.1 扩容后 df 纹丝不动:只扩了 LV、没扩文件系统
这是运维里遇到频率最高的"故障":lvextend明明加了 100G,df -h依然显示原来的容量。排查思路是从块设备层往下看:先lsblk确认/dev/mapper/vg_data-lv_data的大小确实变成 200G 了,再检查文件系统层有没有执行过xfs_growfs或resize2fs。绝大多数情况都是只扩了 LV 忘了扩文件系统,补上最后一步就正常了。这类问题的本质是 LVM 和文件系统各自维护一套容量元数据,命令必须成对使用。
5.2 fstab 写错 UUID,开机直接进救援模式
前面在应急修复环节讲过,这里想补充的是预防细节。很多人喜欢手敲 UUID,容易漏字符;正确做法是先把blkid的输出复制到文本编辑器,再整行粘贴进 fstab。改完 fstab 后直接重启是高风险动作,正确顺序是先mount -a模拟挂载,再查systemctl status确认没有挂载失败的服务。如果机器已经起不来,用单用户模式或救援模式救回来之后,记得把 fstab 里所有裸设备名全部换成 UUID,彻底消除盘符漂移隐患。
5.3 误格式化数据盘:脚本变量的深刻教训
我见过一次因为批量脚本里盘符写错,把存着半年备份的数据盘直接格式化的案例。排查链路非常痛苦:先看监控发现某个目录消失,再翻历史命令和操作日志,最后确认是脚本里变量赋值错误导致mkfs作用到了错误盘符。能分享的教训只有两点:一是脚本里绝对不能出现裸盘符,必须用变量加白名单校验;二是重要数据一定有多份副本,异机备份比任何操作习惯都可靠。格式化类操作在脚本里最好加一道交互确认,由人工二次确认盘符和文件系统类型,避免批量执行的连锁反应。
5.4 目标忙、盘符漂移与其他隐蔽问题
umount提示目标忙是最常见的隐蔽问题,本质是挂载点被进程占用。用lsof定位后,会发现很多是日志进程或数据库连接导致的,处理完进程再卸载就顺畅了。另外盘符漂移在带多块数据盘的物理机上特别常见,重启前后sdb和sdc可能对调,这就是为什么所有持久化挂载都必须用 UUID。还有一个坑是系统里同时存在多个同卷组名的 LVM 卷组,vgimport或vgscan时容易混淆,建议卷组命名时带上业务标识,比如vg_data、vg_archive,避免后续识别开销。
最后再说一个自己的习惯:新装服务器时,不管当时空间够不够,我都会把整块盘送进 LVM,再切逻辑卷。分区阶段多花五分钟,一年后可能就省下一次通宵扩容。磁盘管理的核心不是锦上添花,而是让系统在最坏情况下也能优雅恢复。希望这些经验能帮你少踩几个我已经替你踩过的坑。