1月15号,很多团队刚做完年前最后一轮版本发布,说实话这时候最怕的不是新功能出bug,而是存量机器突然闹情绪。我今年遇到的第一波集中故障,全是磁盘相关的:根分区快写满了,备份盘挂载点不知什么时候掉了,还有一台机器因为 fstab 写错直接卡在启动阶段。趁着处理完这些问题的热乎劲,把 Linux 磁盘管理里最常用到的那一整套东西按实际干活顺序整理出来:查设备、分区分卷、格式化、挂载、排查空间、在线扩容。不是纯命令罗列,重点是讲清楚每一步为什么这么做,以及哪些坑是文档里不会写但我们肯定会踩到的。
先把目标定位一下:这篇内容适合刚接手服务器的新运维、经常要在 Linux 上处理数据盘的后端开发,也适合准备面试时想系统过一遍磁盘知识的人。看完之后面对一台陌生机器,你至少能安全地确认“这块盘是什么、能不能动、动了之后怎么恢复”。
1. 先搞清机器上有哪些盘和分区,再决定动不动刀
很多人一上来就 fdisk -l,看到 /dev/sdb 就直接分区,这种操作在空闲的测试机上没问题,在存量机器上就很容易出事。因为你看到的设备名并不是一个稳定标识,系统每次启动时对设备的枚举顺序可能变化,尤其是有多块同型号硬盘或虚拟化环境里挂载了多个磁盘的时候。
1.1 用 lsblk 一分钟看清设备树
我接手的每台机器,第一命令永远是 lsblk,而不是 fdisk。原因很简单,lsblk 输出非常直观,能直接展示磁盘、分区、挂载点的树状关系:
bash复制lsblk
典型输出是这样:
text复制NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 447.1G 0 disk
├─sda1 8:1 0 512M 0 part /boot/efi
├─sda2 8:2 0 119.2G 0 part /
└─sda3 8:3 0 327.4G 0 part /home
sdb 8:16 0 3.7T 0 disk
└─sdb1 8:17 0 3.7T 0 part /data
如果加 -f 参数,还能额外显示文件系统类型和 UUID:
bash复制lsblk -f
这个参数非常关键。因为后面写 /etc/fstab 的时候既可以用设备路径,也可以用 UUID。而设备路径可能漂移,UUID 是文件系统创建时生成的唯一标识,稳定性高得多。
当机器使用 NVMe 盘时,设备名会变成 nvme0n1、nvme0n2 这种形式,分区后缀是 p1、p2。比如:
text复制nvme0n1 259:0 0 931.5G 0 disk
├─nvme0n1p1 259:1 0 512M 0 part /boot/efi
└─nvme0n1p2 259:2 0 931G 0 part /
虚拟化环境里则可能是 vda、vdb,云盘默认也是这个套路。所以别把 sda 当成永远不变的名字,它只是“当时识别到的某个设备”。
1.2 设备别名的正确查看方式
想要精确区分物理盘,最稳妥的做法是查看 /dev/disk/by-id/ 或 /dev/disk/by-uuid/ 目录:
bash复制ls -l /dev/disk/by-id/
这里能看到硬盘的厂商、型号、序列号与设备名的对应关系。生产环境里做数据盘迁移时,不要靠“我猜 sdb 是那块 4T 的盘”,而应该先确认序列号或 WWN。多盘机器上搞错目标盘,后果是不可逆的。
另外还需要确认系统盘和数据盘的边界。我见过有人把云主机里的系统盘当作空数据盘重新格式化,发现时所有业务代码已经一起消失了。建议先用 lsblk 看挂载点,凡是挂着 /、/boot、/var 的盘,都不要当作可随意初始化的对象。
1.3 用 df 和 du 分别判断“文件系统满没满”和“目录占了多少”
df 和 du 是一对经常被混淆的命令。df 是站在文件系统角度,统计整个分区的已用空间、剩余空间、挂载点;du 则是站在目录树角度,统计每个目录实际占用。
bash复制df -hT
du -sh /data/*
两者统计结果不一致是非常正常的。原因包括:删除文件但进程仍然占用、日志被 truncate 之后文件系统没释放、以及挂载点下层存在被覆盖的旧目录。日常排查要学会两条腿走路,先用 df 定位到哪个分区满了,再用 du 顺着目录往下找大文件。
提示:无论多急,都不要在没看过
df -h和lsblk -f的情况下直接执行 mkfs、fdisk 这类破坏性命令。先花两分钟看清现状,能避免绝大多数误操作。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 分区这步不要拍脑袋:MBR 和 GPT 决定后续容量上限
分区表是整个磁盘管理中最容易忽略但又最影响未来的部分。老一代人习惯用 fdisk 创建 MBR 分区表,但 MBR 有几个硬限制:单盘最大只能管理 2TB 左右,主分区最多 4 个。现代服务器上动不动就是 4T、8T,甚至单块 16T 的 SAS 盘,还继续用 MBR 就是在给自己挖坑。
2.1 MBR 与 GPT 怎么选
GPT 是 UEFI 时代的标准分区表,最大支持 18EB 容量,理论上可以创建 128 个主分区。只要机器不是十几年前的老 BIOS 引导环境,数据盘统一用 GPT 不会有问题。
| 对比维度 | MBR | GPT |
|---|---|---|
| 最大磁盘容量 | 约 2TB | 极大,实际受文件系统限制 |
| 主分区数量 | 最多 4 个 | 默认 128 个 |
| 引导兼容性 | 传统 BIOS 可用 | UEFI 引导,也支持部分 BIOS 场景 |
| 数据可靠性 | 分区表无冗余 | 头尾冗余,带 CRC 校验 |
| 适用场景 | 老旧系统、兼容旧设备 | 现代 Linux 服务器、大容量数据盘 |
现在拿到一块 4T 数据盘,直接创建 GPT 分区表基本没争议。如果是给嵌入式设备、老工控机做启动盘,才需要回头考虑 MBR。还有一些双系统或与 Windows 混用的移动硬盘场景,需要考虑对方机器的引导方式,但不能为了兼容 Windows 而放弃 GPT,因为 Windows 7 以后的系统对 GPT 支持已经很好。
热搜里常看到的“Win10 磁盘管理转换成 GPT 硬盘是灰色”,本质就是盘上已经有 MBR 分区且非空,Windows 不允许直接转换。解决办法是在 Windows 下先备份数据后 clean 整块盘,或者直接在 Linux 里用 parted 重做 GPT 分区表,然后重新分区。如果在 Linux 侧处理,操作前同样要注意备份。
2.2 fdisk 处理 2T 以下磁盘的最常用流程
fdisk 是运维最熟悉的分区工具,交互式操作对新手非常友好。例如给 /dev/sdb 创建 GPT 分区表并划分一个分区:
bash复制fdisk /dev/sdb
进入交互界面后依次输入:
text复制g # 创建 GPT 分区表;如果只输 n 默认是 dos 即 MBR
n # 新建分区
1 # 分区号
回车 # 起始扇区默认
回车 # 结束扇区默认,表示用完整块盘
w # 保存退出
如果只分一个区,并且希望这个分区占满整块磁盘,上述操作就够了。分完之后系统可能还没有立刻刷新分区表,多数发行版会自动刷新,没刷新时可手动执行 partprobe:
bash复制partprobe /dev/sdb
lsblk
2.3 超过 2T 或需要脚本化时直接用 parted
fdisk 对 GPT 的支持也不错,但遇到超大容量盘或需要非交互脚本化操作时,我更推荐 parted。parted 直接一步到位:
bash复制parted -s /dev/sdb mklabel gpt
parted -s /dev/sdb mkpart primary xfs 0% 100%
第一条命令创建 GPT 分区表,第二条从磁盘起始位置到 100% 创建分区。这里的 xfs 只是给 parted 一个提示用的文件系统类型标识,并不会真的格式化,真正格式化还是靠后面的 mkfs。
如果磁盘上有多个分区要规划,可以写成:
bash复制parted -s /dev/sdb mklabel gpt
parted -s /dev/sdb mkpart primary 0% 50%
parted -s /dev/sdb mkpart primary 50% 100%
这种方式尤其适合批量初始化一批机器,可以直接塞进脚本里循环跑。记住:parted 的 mklabel 选项是整盘重建分区表的操作,执行后原有分区信息会全部消失,生产环境慎用。
3. mkfs 不只是选个文件系统那么简单
分区是对一块物理盘做切割,格式化则是在分区上建立文件系统。这个步骤看起来只是一个 mkfs 命令,但文件系统类型直接决定了你日后能做什么操作:能不能在线扩容、能不能缩容、能不能做快照、对大量小文件是否友好。
3.1 ext4、xfs、btrfs之间如何做决定
CentOS 7 之后的默认文件系统早就换成了 xfs,Ubuntu 桌面版默认 ext4。两者没有绝对的优劣,更准确的说法是使用场景有差异。
| 文件系统 | 适合场景 | 优势 | 需要注意的点 |
|---|---|---|---|
| ext4 | 通用 Linux 数据盘、根文件系统 | 成熟稳定,工具链丰富 | 单文件性能相对 xfs 弱一些 |
| xfs | 大规模数据存储、大文件读写 | 高吞吐,支持在线扩大 | 不能缩小,缩减分区只能靠重做 |
| btrfs | 需要快照、子卷、校验功能的存储 | 功能丰富,支持写时复制 | 运维知识门槛高,小版本兼容性需关注 |
如果你拿不定主意,数据盘就直接 xfs,根分区按发行版默认即可。xfs 对 T 级容量文件系统的支撑能力很强,而且扩展非常方便,只需要 xfs_growfs 一条命令。缺点是不能缩容,所以规划数据卷时一开始不要把 LVM 逻辑卷建得过大,否则后面想缩小几乎没有简单路径。
格式化命令通常是:
bash复制mkfs.xfs /dev/sdb1
如果看到盘上有旧文件系统,mkfs 会提示有内容,这时需要确认是不是真的该格式化。确认无误后可以用 -f 强制,但生产环境一定不要随手加 -f:
bash复制mkfs.xfs -f /dev/sdb1
很多误格式化事故就是 mkfs.xfs -f 打得太顺手造成的。正确的习惯是先 blkid 看一下这块分区上原本是什么内容,确认无用后才格式化。
3.2 block size 和 label 的影响
文件系统有个底层参数叫块大小。默认 4K 能覆盖绝大多数场景,但如果你的业务是大量小文件,比如消息队列积压目录、对象存储元数据区,可以考虑用更小的块或直接采用适应小文件的文件系统。如果业务是视频流、数据库备份这类大文件持续写入,那 xfs 默认参数完全够用。
格式化时给磁盘打标签是个好习惯:
bash复制mkfs.xfs -L data_disk /dev/sdb1
blkid /dev/sdb1
加了 -L 之后,lsblk -f 的 LABEL 列会有可读性更好的名字。以后维护多盘机器时,label 能帮你快速识别哪块盘是干什么的。
3.3 格式化之后别急着写 fstab,先手动挂载验证一次
创建好文件系统后,我习惯先手动挂载试运行几分钟:
bash复制mkdir -p /data
mount /dev/sdb1 /data
df -h /data
这一步能提前暴露很多问题:文件系统创建失败、分区设备名搞错、挂载点权限异常等。确认读写正常后,再把它写进 fstab,避免把启动流程搞挂。
提醒:mkfs 只能对分区执行,不能对整块盘执行。如果你直接
mkfs.xfs /dev/sdb而不是/dev/sdb1,有些版本会拒绝,有些则会提示。这恰好是保护机制,别强行绕过它。正确流程是先分区,再对分区做文件系统。
4. fstab 写错导致的启动事故,怎么快速自救
挂载这个动作本身没什么难度,难度在于把挂载关系固定下来,让它开机自动生效。这就引出 /etc/fstab 这个文件。fstab 一旦写错,机器启动时可能出现挂载失败,某些发行版会直接掉进 emergency mode。2026 年第一波故障里,我就帮同事抢救了一台这样的机器。
4.1 fstab 每一列的真正含义
fstab 每一行代表一个挂载配置,共六列。以一条常见配置为例:
text复制UUID=7f6c1c9e-8e3d-4b2a-9c3f-1d0e2a3b4c5d /data xfs defaults,nofail 0 2
按顺序拆开就是:
| 列号 | 含义 | 示例值 | 注意事项 |
|---|---|---|---|
| 1 | 被挂载的设备 | UUID=... | 优先用 UUID 而不是 /dev/sdb1 |
| 2 | 挂载点 | /data | 目录必须存在 |
| 3 | 文件系统类型 | xfs | ext4 就写 ext4 |
| 4 | 挂载选项 | defaults,noatime,nofail | 多个选项用逗号分隔 |
| 5 | 是否备份 | 0 | 0 表示不备份 |
| 6 | fsck 检查顺序 | 2 | 根分区为 1,其他分区为 2 |
在选择第一列时,推荐直接写 UUID。这样即使系统启动后盘符变成 sdc、sdd,只要 UUID 没变,挂载就不会乱。获取 UUID 的方法很简单:
bash复制blkid /dev/sdb1
lsblk -f
4.2 挂载选项里的 nofail 和 noatime 到底要不要加
默认选项 defaults 已经包含 rw、suid、dev、exec、auto、nouser、async 这些基础项。对普通数据盘,我习惯额外加两个:
- noatime:不更新访问时间,可以减少大量写 IO。
- nofail:即使设备不存在,系统启动时也不会因此阻塞或进入救援模式。
nofail 在服务器上特别实用。如果某块备份盘偶尔没有被插上,或者某些外置存储因为硬件原因延迟出现,不带 nofail 的 fstab 可能导致启动卡住。当然,如果设备确实故障了,你也希望日志里能看到提示,而不是无声跳过,所以这个参数适合“可缺省的数据盘”,不适合根分区。
完整示例:
text复制UUID=7f6c1c9e-8e3d-4b2a-9c3f-1d0e2a3b4c5d /data xfs defaults,noatime,nofail 0 2
修改完 fstab 之后,千万不要直接 reboot。应该先执行:
bash复制mount -a
这个命令会按 fstab 配置重新加载所有还没挂载的设备。如果没有报错,说明语法基本没问题。再进一步可以卸载某个挂载点后重新 mount -a 验证:
bash复制umount /data
mount -a
df -h /data
4.3 启动掉进 emergency mode 之后的完整自救流程
如果 fstab 写错导致机器启动失败,别慌。大多数情况下系统会提示“You are in emergency mode”并给出 root 密码登录入口。原因是某个挂载项失败,系统无法进入正常的多用户环境。
登录后第一件事是把根分区重新挂载为可读写。因为此时根分区通常以只读方式挂载,直接编辑 fstab 会提示文件系统只读:
bash复制mount -o remount,rw /
然后打开 fstab:
bash复制vim /etc/fstab
把刚写的可疑行注释掉或修正,重点检查设备 UUID、挂载点目录是否存在、文件系统类型是否匹配。保存退出后执行:
bash复制mount -a
如果已经没有错误,再正常重启验证一次。还有一种情况是挂载点目录不存在,导致挂载失败,这时要先创建目录:
bash复制mkdir -p /data
整个排查链路看起来简单,但我见过不少同事在 emergency mode 里卡住,主要是忘记了根分区是只读挂载这个细节。记住,启动异常时先 mount -o remount,rw /,再去改文件,否则编辑了也白编辑。
5. “磁盘慢、空间不够、找不到元凶”的真实排查和扩容场景
磁盘管理的重头戏往往不是新盘上线,而是存量盘出问题。群里最常听到的一句话是:“我的根分区满了,但不知道什么文件占了空间。”要解决这类问题,不能只靠 df 看一眼就完事。
5.1 空间排查的四板斧
第一板斧是先看整体使用率:
bash复制df -h
df -i
df -h 管空间,df -i 管 inode。很多人只盯空间使用率,忽略 inode。inode 耗尽是另一种“No space left on device”,此时 df -h 看着明明还有几十 G,但文件就是创建不出来,原因是文件系统的索引节点已经被大量小文件占满。
第二板斧是逐级进入目录找大文件:
bash复制du -h --max-depth=1 / | sort -hr | head -20
这个命令会从根目录开始列出各级目录占用大小,并排出前 20 名。如果根分区在 /var,就继续深入:
bash复制du -h --max-depth=1 /var | sort -hr | head -20
第三板斧是检查被删除但仍被进程占用的文件。在 Linux 中,进程打开某个文件后,即使你从磁盘上把这个文件 rm 了,空间也不会立即释放,因为该文件仍被文件描述符引用。排查方法:
bash复制lsof +L1
看到类似 (deleted) 的文件就是问题源。对应解决办法是重启相关进程,或者重启服务,空间才会真正还给文件系统。
第四板斧是清理日志和包管理器缓存。常见的大头是 /var/log/journal、nginx access log、Docker overlay 目录、旧内核包。清日志时不要盲目删除,通常用 truncate 方式清空:
bash复制truncate -s 0 /var/log/nginx/access.log
systemd 日志可以按容量限制:
bash复制journalctl --vacuum-size=200M
5.2 明确是 inode 耗尽后的处理方法
如果你确认 df -i 输出中 IUse% 接近 100%,那就需要在存放大量小文件的目录里做粒度分析。小文件常出现在 /tmp、/var/spool/postfix/maildrop、容器存储目录、对象存储缓存目录等位置。
找到目录后用 find 统计文件数量:
bash复制find /var/spool/postfix/maildrop -type f | wc -l
find /data/cache -type f | wc -l
根据业务判断能否直接删除或归档。删除大量小文件很考验命令效率,推荐用 find 配合 delete 参数:
bash复制find /data/cache -type f -mtime +90 -delete
这种删除方式比先 ls 再 rm 要好很多,避免参数过长的问题。
5.3 从一块普通数据盘到一个可扩容的 LVM 逻辑卷
如果发现分区空间不够,传统做法是再加一块盘,挂到一个新目录。但更优雅的做法是启用 LVM,把多块物理盘纳入同一个卷组,逻辑卷可以随时扩大。
假设原来有一块数据盘 /dev/sdb,已经用 LVM 分好卷组 vgdata,逻辑卷 lvdata 挂载在 /data。现在容量不够,新增了一块 /dev/sdc,扩容步骤如下:
把新盘创建为物理卷:
bash复制pvcreate /dev/sdc
把物理卷加入已有卷组:
bash复制vgextend vgdata /dev/sdc
扩展逻辑卷,增加 2T 空间:
bash复制lvextend -L +2T /dev/vgdata/lvdata
文件系统也要跟着扩大。xfs 用 xfs_growfs,ext4 用 resize2fs:
bash复制xfs_growfs /data
如果创建逻辑卷时就想把整块新盘全部分配给 /data,可以直接:
bash复制lvresize -l +100%FREE /dev/vgdata/lvdata
xfs_growfs /data
而使用 ext4 时扩展命令是:
bash复制resize2fs /dev/vgdata/lvdata
这里需要特别强调:xfs 只支持扩大,不支持在线缩小。如果你前期规划不当,把一个 xfs 逻辑卷建得过大,后面想缩回来就得备份数据、删除逻辑卷、重新创建。所以用 LVM 管理数据盘时,逻辑卷的初始大小要适度,留出卷组内的空闲空间,以便后续按需增长。
LVM 的价值就像仓库里先修了多个隔断墙,每个隔断的容量随时可以调整。你不必每次换个大仓库就搬一遍所有货物。这也是为什么生产环境我建议把数据盘统一纳入 LVM 管理,而不是直接对物理分区做文件系统。
6. 处理完这些突发问题后,我留下的小习惯
操作记录多了之后会发现,磁盘管理相关的故障往往不是命令不会,而是对风险缺少敬畏。我给自己定了几条规矩,也分享给你参考。
6.1 高危操作前必查序列号和 UUID
所有可能清除数据的分区、格式化、分区表重建操作,执行前必须执行:
bash复制lsblk -o NAME,SIZE,MODEL,SERIAL,TRAN,MOUNTPOINTS,FSTYPE
通过 SIZE、MODEL、SERIAL 确认这块盘的确是目标盘。物理机可以看硬盘序列号标签,虚拟机能通过控制台确认磁盘 ID,两边核上了再动手。如果只是靠“我记得 sdc 是那块新盘”这种直觉,风险太高。
6.2 fstab 改完必须 mount -a 验证
我现在把“改完 fstab 以后 reboot 前需要验证”当成肌肉记忆。哪怕只加了一行新配置,也要先 mount -a,再 findmnt --verify --verbose 检查 fstab 合法性。
findmnt 验证命令是很多人不知道的好工具:
bash复制findmnt --verify --verbose
它能帮你检查 fstab 里哪些设备无法找到、哪些挂载点不存在、哪些文件系统类型无法识别。不用等到重启被系统教育。
6.3 大量小文件目录要单独规划
如果你的业务会产生海量小文件,比如消息队列落地目录、临时图片目录,一定要把它规划为独立分区或独立逻辑卷,并监控 inode 使用率。平时监控如果只看空间不看 inode,等到创建不了文件才去排查,业务早就受到了影响。这一点面试也常考,但实际工作中更值得形成习惯。
6.4 给新盘上线流程做一张自己的检查单
我现在每上一块新数据盘,至少按这个顺序走一遍,缺一步都要停下来:
- lsblk 确认设备树,记录序列号和类型。
- 确定分区表:数据盘默认 GPT。
- 用 parted 或 fdisk 创建分区。
- partprobe 刷新分区表。
- 确认分区名:lsblk 验证。
- mkfs 创建文件系统,顺手加 label。
- blkid 记录 UUID。
- 创建挂载点并手动挂载。
- 写 fstab,用 nofail 参数。
- mount -a 验证,最后重启前再测一次。
这套流程看着繁琐,但它能保证你面对几十台机器时不乱。我实际用下来,每块盘从裸盘到可用,最多多花五分钟,这五分钟买的是“第二天机器不会因为 fstab 问题起不来”的安心。
磁盘管理这个东西,越往后越会发现,核心不是会敲几个命令,而是知道每一步背后在做什么、会造成什么影响。希望这篇带着实战气的整理,能让你下次处理 Linux 磁盘问题时少走几个弯路,至少别再让一台数据盘挂载点悄悄消失到第二天上班才知道。
