3. 磁盘与文件系统管理:从分区到LVM的完整链路
磁盘管理这件事,说白了就是给服务器安排「储物空间」。你买来一块硬盘,不能直接用——得先划区域(分区)、再格式化(建文件系统)、最后挂到目录树上(挂载)。如果以后空间不够了,还得能动态扩容。这就是本章要讲的核心。
我在生产环境里见过太多因为磁盘规划不合理导致的故障。有一次,某台数据库服务器根分区写满,整个服务直接挂了。嗯,从那以后,我对磁盘管理就特别较真。
本章知识体系:从物理磁盘到逻辑卷的完整链路,每一步都有对应的工具和坑。
3.1 磁盘分区:fdisk 实战
拿到一块新硬盘,第一步就是分区。我个人习惯先用 lsblk 看一眼磁盘列表,确认设备名。
# 查看所有块设备
lsblk
# 输出示例
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 100G 0 disk
├─sda1 8:1 0 1G 0 part /boot
├─sda2 8:2 0 49G 0 part /
└─sda3 8:3 0 50G 0 part /data
sdb 8:16 0 200G 0 disk # 新加的盘,还没分区
然后对 /dev/sdb 执行 fdisk:
fdisk /dev/sdb
# 进入交互模式后,常用命令:
# n - 新建分区
# p - 打印分区表
# d - 删除分区
# w - 写入并退出
# q - 不保存退出
我的习惯:生产环境分区时,我会把系统盘和数据盘分开。系统盘用 ext4,数据盘用 xfs。这样即使数据盘出问题,系统还能启动。
举个例子,给 200G 的 sdb 分两个区:
# 交互过程(简化)
Command: n
Partition type: p (primary)
Partition number: 1
First sector: (默认)
Last sector: +100G # 第一个分区 100G
Command: n
Partition type: p
Partition number: 2
Last sector: (默认) # 剩余全给第二个分区
Command: w # 写入分区表
分区完成后,记得让内核重新读取分区表:
partprobe /dev/sdb # 或者 reboot
⚠️ 注意:fdisk 操作的是分区表,一旦 w 写入就生效了。我曾经在测试环境手滑把分区表写错了,还好有备份。建议操作前先用 fdisk -l 确认磁盘信息。
3.2 文件系统创建:mkfs 的选择
分区建好了,接下来要「格式化」——专业说法是创建文件系统。Linux 下用 mkfs 系列命令。
| 文件系统类型 | 适用场景 | 最大文件大小 | 最大分区大小 |
|---|---|---|---|
| ext4 | 通用场景,兼容性好 | 16TB | 1EB |
| xfs | 大文件、高并发,RHEL/CentOS 7+ 默认 | 8EB | 8EB |
| btrfs | 高级功能(快照、压缩、校验) | 16EB | 16EB |
我个人在服务器上首选 xfs,尤其是数据库或日志存储场景。ext4 更适合 /boot 分区或嵌入式环境。
# 创建 ext4 文件系统
mkfs.ext4 /dev/sdb1
# 创建 xfs 文件系统
mkfs.xfs /dev/sdb2
# 创建时指定标签(方便识别)
mkfs.ext4 -L data_disk /dev/sdb1
mkfs.xfs -L log_disk /dev/sdb2
小技巧:创建 xfs 时,如果磁盘是 SSD,可以加 -f 强制覆盖已有文件系统。另外,xfs 不支持缩小,只能扩大——规划时要想清楚。
3.3 挂载:让文件系统可用
文件系统建好了,但 Linux 还不能直接用。你得把它「挂」到某个目录上。
# 临时挂载
mount /dev/sdb1 /mnt/data
# 查看挂载情况
df -h
mount | grep sdb
但重启后挂载就丢了。要永久生效,得写 /etc/fstab:
# 先获取 UUID(比设备名更稳定)
blkid /dev/sdb1
# 输出:/dev/sdb1: UUID="abc123..." TYPE="ext4"
# 编辑 /etc/fstab,添加一行
UUID=abc123... /mnt/data ext4 defaults 0 2
| fstab 字段 | 说明 | 示例 |
|---|---|---|
| 设备 | 推荐用 UUID 或 LABEL | UUID=abc123 |
| 挂载点 | 必须存在的目录 | /mnt/data |
| 文件系统类型 | ext4 / xfs / swap 等 | ext4 |
| 挂载选项 | defaults 包含 rw, suid, dev, exec, auto, nouser, async | defaults |
| dump | 是否备份(0 不备份) | 0 |
| pass | fsck 检查顺序(1 根分区,2 其他,0 不检查) | 2 |
⚠️ 避坑指南:我曾经在 fstab 里写错了设备名,导致服务器重启后无法进入系统。后来我养成了一个习惯——每次修改 fstab 后,先用 mount -a 测试一下,确认没问题再重启。
3.4 LVM 逻辑卷管理:动态扩容的利器
传统分区有个硬伤:分区大小固定。比如你给 /home 分了 50G,结果用满了,想扩容?得删分区重建,数据还得备份恢复。太折腾了。
LVM 就是来解决这个问题的。它把物理磁盘抽象成「逻辑卷」,你可以随时在线扩容,甚至跨磁盘合并。
3.4.1 LVM 核心概念
- PV(Physical Volume,物理卷):就是磁盘分区或整块磁盘,用
pvcreate初始化。 - VG(Volume Group,卷组):多个 PV 组成一个资源池。
- LV(Logical Volume,逻辑卷):从 VG 里切出来的「虚拟分区」,可以格式化后挂载。
打个比方:PV 是砖头,VG 是砖头堆,LV 是从砖头堆里砌出来的房间。房间不够大?再往砖头堆里加砖头就行。
3.4.2 实战:创建 LVM
# 1. 准备物理卷(假设有 /dev/sdb1 和 /dev/sdb2)
pvcreate /dev/sdb1 /dev/sdb2
# 查看 PV
pvs
pvdisplay
# 2. 创建卷组
vgcreate vg_data /dev/sdb1 /dev/sdb2
# 查看 VG
vgs
vgdisplay
# 3. 创建逻辑卷(从 vg_data 中切出 50G)
lvcreate -L 50G -n lv_app vg_data
# 查看 LV
lvs
lvdisplay
# 4. 格式化并挂载
mkfs.xfs /dev/vg_data/lv_app
mount /dev/vg_data/lv_app /opt/app
# 写入 fstab(用 /dev/mapper/vg_data-lv_app 路径)
echo "/dev/mapper/vg_data-lv_app /opt/app xfs defaults 0 2" >> /etc/fstab
3.4.3 在线扩容
这是 LVM 最爽的地方。假设 lv_app 空间不够了:
# 1. 先确保 VG 有空闲空间
vgs
# 输出:VG #PV #LV #SN Attr VSize VFree
# vg_data 2 1 0 wz--n- 199.99g 149.99g
# 2. 扩展 LV(增加 20G)
lvextend -L +20G /dev/vg_data/lv_app
# 3. 让文件系统感知变化
# ext4 用 resize2fs
resize2fs /dev/vg_data/lv_app
# xfs 用 xfs_growfs
xfs_growfs /opt/app
# 4. 验证
df -h /opt/app
我的经验:生产环境扩容时,我从来不用 -L 70G(指定绝对值),而是用 -L +20G(增加量)。这样即使手误,也不会把卷缩得太小。另外,xfs 扩容后不需要卸载,但 ext4 在某些内核版本下需要。
3.4.4 缩容(谨慎操作)
⚠️ 重要提醒:xfs 不支持缩容!ext4 虽然支持,但必须先卸载文件系统,而且有数据丢失风险。我在生产环境从不做缩容操作——宁可多留点空间,也不冒险。
# ext4 缩容示例(仅作了解,不建议生产使用)
umount /dev/vg_data/lv_app
e2fsck -f /dev/vg_data/lv_app
resize2fs /dev/vg_data/lv_app 30G # 缩小到 30G
lvreduce -L 30G /dev/vg_data/lv_app
mount /dev/vg_data/lv_app /opt/app
3.5 本章小结
磁盘管理是运维的基本功,也是事故高发区。我总结几个关键点:
- 分区规划:系统盘和数据盘分开,预留足够空间给 /var 和 /tmp。
- 文件系统选择:生产环境优先 xfs,小分区或 /boot 用 ext4。
- 挂载规范:fstab 用 UUID,修改后先
mount -a测试。 - LVM 核心:PV → VG → LV 三层抽象,扩容是常态,缩容是禁忌。