刚接手一台新服务器,发现根分区快满了,但明明当初分配了500G空间;或者给某套数据库扩容,明明加了块新硬盘,系统里怎么都看不到容量变化。这类问题在运维和开发工作中太常见了。Linux磁盘管理,说白了就是搞定三件事:让系统认得出硬件、让空间能放文件、让空间不够时不抓瞎。
这篇文章我会从实际运维视角,把磁盘管理的核心链路完整梳理一遍:设备认别、分区规划、格式化、挂载、逻辑卷管理、空间排查、性能监控与故障恢复。每一段都是能被直接拿来用的操作思路,不是罗列命令参数,而是讲清楚每条命令为什么这么用、踩过什么坑。
无论你是刚接触Linux的初学者,还是写过脚本但没摸过生产服务器的开发者,这文章都按“先懂原理、再上手、最后会排查”的顺序来组织,尽量让每层内容都能单独查阅。
1. 先看清你的整体形态:设备、分区、文件系统三层结构
很多教程一上来就叫人敲fdisk,结果新手分不清/dev/sda、/dev/sda1、/dev/mapper/vg0-lv0到底是什么关系。要管好磁盘,脑子里先建一张三层结构图。
1.1 硬件设备:一切从/dev开始
Linux里一切皆文件,物理硬盘挂在/dev下。实体机常见的是sd开头(SATA/SCSI/SAS接口),比如/dev/sda就是第一块硬盘,/dev/sdb是第二块;云服务器或者新式NVMe固态盘,常见的是/dev/vda、/dev/nvme0n1这样的名字。
硬盘本身是块“大饼”,系统不能直接在上面建文件夹,得先分区。分区之后,每个分区的设备名就是/dev/sda1、/dev/sda2这样,数字代表分区编号。如果用了逻辑卷管理(LVM),还会多出一个虚拟设备层,路径变成/dev/mapper/某卷组名-某逻辑卷名,这层后面专门讲。
1.2 分区表:MBR和GPT的选型逻辑
分区表是刻在磁盘最开头的一段元数据,记录着磁盘上有哪些分区、从哪儿开始到哪儿结束。常见的两类是:
- MBR(DOS分区表):老牌方案,兼容性最好,但分区数量有限(主分区最多4个),而且单分区最大只能支持到2TB。不是不能用,是容量天花板太低。
- GPT(GUID分区表):现代方案,支持9.4ZB理论容量,分区数量几乎没有限制,还带冗余的头部信息,比MBR抗损坏。目前新机器、新系统基本默认GPT。
这里必须补一句避坑经验:如果服务器BIOS用的是传统Legacy模式,有些老系统装的时候会指定MBR;UEFI引导的机器基本都用GPT。实际操作中,超过2TB的磁盘必须用GPT,用MBR会导致分出来的区只认到约2.2TB,剩下的空间完全消失。这个坑尤其在扩容数据盘时经常遇到,扩容前最好用parted /dev/sdb print看一下分区表类型。
1.3 文件系统:决定空间怎么管理
分区只是把“大饼”切块,要让文件能读写,还得在分区上建立文件系统。不同文件系统性能特征差异很大:
- ext4:老牌稳健,兼容性极强,小文件读写均衡,适合通用场景,像CentOS 6/7时代默认就是它。
- xfs:高容量、高并发场景表现出色,是目前红帽系(RHEL/CentOS 8+、Rocky、Alma)的默认选择,单文件上限大,适合大文件应用。
- btrfs:带快照、压缩、校验功能,偏向下一代特性,但生产实践量相对少,我一般不轻易在生产上推荐给保守型团队。
- 另外还有ZFS(多用于存储服务器)、swap(交换分区)等,想快速决策的话,纯业务数据盘我通常直接推荐ext4或xfs。
查看文件系统类型很简单:df -hT,或者blkid也能看到。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 分区实操:从lsblk认盘到fdisk/parted切分
分区看似简单,但实际生产里要小心:既有数据的老磁盘不能随便动,新磁盘要先确认盘符,还要想清楚用传统fdisk还是parted。
2.1 第一步先认盘:lsblk教你一眼看懂
lsblk是我使用频率最高的命令之一,它能把磁盘、分区、挂载点的树状关系一口气打出来,比fdisk -l直观得多。
bash复制lsblk
典型输出:
text复制NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vda 253:0 0 100G 0 disk
├─vda1 253:1 0 1G 0 part /boot
└─vda2 253:2 0 99G 0 part
└─centos-root 253:0 0 99G 0 lvm /
看到vda2下面还有一层centos-root,说明根分区不是直接用物理分区,而是走了LVM逻辑卷。这时候用fdisk直接对根分区动手就不合适,应该对逻辑卷层操作。所以认盘先看lsblk能避免很多盲目操作。
新磁盘接入后,系统未必自动识别。比如热插拔的磁盘或者云盘扩容之后,执行lsblk看不到新容量,可以先跑一下:
bash复制echo 1 > /sys/block/sda/device/rescan
或者用partprobe刷新分区表。实在不行就重启或通过云控制台卸载再挂载,不同虚拟化环境刷新方式略有差别。
2.2 fdisk创建分区:2TB以内够用
进入交互式分区工具:
bash复制fdisk /dev/sdb
常用交互命令:
- n:新建分区
- p:查看分区表
- d:删除分区
- w:保存退出
- q:放弃退出
新建一个分区并设置为Linux LVM类型的流程:
text复制Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-..., default 2048): # 直接回车
Using default value 2048
Last sector, +sectors or +size{K,M,G,T,P} (..., default ...): +80G
Command (m for help): t
Selected partition 1
Hex code (type L to list all codes): 8e # 8e 是 Linux LVM
Command (m for help): w
这里注意扇区起始位置用默认值即可,人为去改起始位置反而容易导致分区错位的问题。指定分区大小推荐直接写+80G这种形式,别去手工换算扇区数,容易出错。
2.3大容量磁盘与parted:GPT的必经之路
超过2TB的盘,fdisk已经不能完整支持GPT操作,需要用parted:
bash复制parted /dev/sdc
(parted) mklabel gpt
(parted) mkpart primary 0% 100%
(parted) align-check optimal 1
(parted) print
(parted) quit
小技巧:parted的align-check optimal 1是检查分区是否对齐的,如果显示1 aligned那说明没问题。分区没对齐的话,固态盘和高级格式化盘(4K扇区)性能会掉得厉害,这在老教程里经常被忽略。
3. 格式化与挂载:让空间真正可用
分区完成后,系统其实还不认识这个分区的文件系统,需要格式化,然后挂载到某个目录才算是“能用”。
3.1 mkfs系列:格式化的正确姿势
格式化命令大多长得像mkfs.文件系统类型,例如:
bash复制mkfs.xfs /dev/sdb1
mkfs.ext4 /dev/sdc1
mkfs.xfs -f /dev/sdb1 # -f 表示强制,覆盖已有文件系统
这里有几个实操细节值得注意:
- 格式化是不可逆操作,确认盘符无比重要。我见过同事把数据盘的盘符认串,一条
mkfs.ext4 /dev/sdb1直接把归档库盘给清了,当时整个团队都懵了。格式化前至少执行一次lsblk、blkid确认盘符和当前挂载情况。 - 如果有旧数据需要彻底清除,
dd慢写零太费时,mkfs其实已经覆盖了文件系统超块和关键元数据,普通场景下够用;但如果涉及数据销毁级别的需求,要考虑物理销毁或专业擦除工具,这里不做扩展。 - 对生产大容量磁盘,现在不少人直接用
xfs,挂载参数也更简单,默认就带defaults。
格式化完可以顺手查看文件系统信息:
bash复制blkid /dev/sdb1
输出里有UUID、文件系统类型,这个UUID马上要用到。
3.2 mount与/etc/fstab:自动挂载的完整方案
手动挂载很简单:
bash复制mount /dev/sdb1 /data
但重启就没了。要永久生效,得写/etc/fstab。我推荐用UUID而不是设备名来写,因为设备名在系统重启后可能乱序(插拔顺序变化导致/dev/sdb变成/dev/sdc),UUID则恒久不变。
先查看UUID:
bash复制blkid /dev/sdb1
假设输出为:
text复制/dev/sdb1: UUID="3b7a8f2c-8f2a-4a1e-9d5c-66f7c2e1a2b3" TYPE="xfs"
在/etc/fstab末尾加一行:
text复制UUID=3b7a8f2c-8f2a-4a1e-9d5c-66f7c2e1a2b3 /data xfs defaults 0 0
六个字段分别是:设备标识、挂载点、文件系统类型、挂载参数、是否dump备份、是否开机fsck。最后两个数字一般写0 0,根分区可写1 1或根据实际发行版要求。
写完fstab别急着重启,先做一次验证:
bash复制mount -a
mount -a会把/etc/fstab中所有条目自动挂载一遍。如果语法有误,命令会直接报错,且不会把系统搞挂到无法启动。我每次改完fstab都习惯性跑一下这个命令,已经养成肌肉记忆了。
3.3 挂载参数里的门道:noatime、nofail与_netdev
/etc/fstab第四列可配置的参数影响很大:
noatime:不更新文件的访问时间戳。对数据库、日志类读写频繁的场景有明显性能改善,也减少了磁盘写放大。nofail:挂载失败不阻断系统启动。这个对数据盘很重要——假设某个数据盘在开机时掉了,如果不加nofail,系统会卡在挂载阶段甚至直接进不了系统,加上nofail就只报错跳过,至少业务系统还能起来。_netdev:告诉系统这是一个网络文件系统(NFS等),要等网络就绪后再挂载,避免开机时网络没起来导致挂载失败。nodiratime:不更新目录访问时间,通常和noatime一起用。
提示:云服务器挂载数据盘的
fstab条目,建议至少带上nofail,否则某次云盘卸载或异常掉线时,实例可能无法正常启动,这是个容易踩的大坑。
4. 逻辑卷管理:把空间盘活的核心技能
直接使用物理分区有个硬伤:分区一旦建立,往后的扩容、缩容就很麻烦。比如根分区当初只分了30G,现在满了,就算后面加了块500G的新硬盘,根分区也吃不到。用LVM的逻辑卷管理可以绕过这个限制,它相当于在物理分区和文件系统之间加了一层“逻辑橡皮泥”,可以随时捏形状。
4.1 概念三件套:PV、VG、LV
- PV(物理卷):一个物理分区或整块磁盘,标记为可供LVM使用的“原材料”。
- VG(卷组):若干个PV聚合成一个大的资源池,相当于把多块硬盘混在一起变成一个仓库。
- LV(逻辑卷):从VG里切出来的一块空间,格式化成文件系统后挂载使用,相当于从大仓库里划出的一块专属区域。
正常使用中只关注LV即可,因为LV才是最终挂载后看到的“盘”。Linux安装时如果自动分区,常见布局就是建一个大PV,然后把整个VG空间划给一个根LV,这就是lsblk里看到centos-root这类名字的由来。
4.2 从零创建一个LVM体系
假设新盘是/dev/sdb,第一步先做PV:
bash复制pvcreate /dev/sdb1
一个分区只能做一个PV,如果你嫌分区麻烦,整块盘也能直接建PV(前提是盘上没重要的已有数据):
bash复制pvcreate /dev/sdc
然后建VG:
bash复制vgcreate vg_data /dev/sdb1 /dev/sdc
注意第一个参数是卷组名,我一般叫vg_data或vg_home,一看就知道用途。接着从VG里切LV:
bash复制lvcreate -L 200G -n lv_data vg_data
-L 200G指定大小,-n指定逻辑卷名字。也可以把VG所有剩余空间都划给LV:
bash复制lvcreate -l 100%FREE -n lv_data vg_data
接下来就是熟悉的格式化挂载流程:
bash复制mkfs.xfs /dev/vg_data/lv_data
mount /dev/vg_data/lv_data /data
再看一眼lsblk,你会看到逻辑卷层级已经出现了。以后扩容就不需要动分区,直接在VG这一层操作。
4.3 在线扩容:让文件系统“变大”的完整流程
这是LVM最大的卖点:空间不够,不用卸载、不用重启,能在线扩容。
现在lv_data有200G,用着用着只剩10%了,而vg_data里还有300G空闲。先看VG剩余容量:
bash复制vgs
确认有Free空间后,把LV扩到500G:
bash复制lvextend -L 500G /dev/vg_data/lv_data
注意:这一步只是扩大了LV的容量,文件系统本身还没感知到新空间。如果是ext4:
bash复制resize2fs /dev/vg_data/lv_data
如果是xfs:
bash复制xfs_growfs /data
xfs不能在线缩容,只能扩容,缩容方案是先备份再重建。ext4理论上支持离线缩容,但生产上我极少这么干,因为风险高、流程长,不如重新搞一个合适大小的LV然后把数据迁过去。
对于整块盘新加PV,还可以动态加入VG,也算扩展容量常用路线:
bash复制pvcreate /dev/sdd
vgextend vg_data /dev/sdd
执行完vgextend,VG空间立即增大,后续直接lvextend就能用了。
4.4 快照:低成本备份与恢复的时间机器
LVM快照不是文件级备份,而是块级的一致快照。它主要价值在于:做重要操作前(比如升级数据库、大批量变更数据),先拍一个快照,操作出问题可以快速回滚。
创建快照的命令:
bash复制lvcreate -L 20G -s -n lv_data_snap /dev/vg_data/lv_data
-s表示创建快照,-L 20G是给快照预留的空间。快照初始不占用实际空间,只有当原LV数据发生变化,被覆盖的旧数据才会写入快照区,所以给快照预留原数据变更量的空间即可。
恢复方式:将当前LV卸载后,用快照覆盖回去:
bash复制umount /data
lvconvert --merge /dev/vg_data/lv_data_snap
mount /data
只有原LV是静态数据或变更量小于快照预留空间时,这个流程才安全。如果快照空间写满了,快照会自动失效,数据一致性就无法保证。所以生产环境用快照,一定要监控快照使用率,这细节容易翻车。
5. 磁盘空间告急:从df到du的排查路径
磁盘管理里最频繁的救火场景就是空间满了。处理这类问题,关键不是盲目删文件,而是搞清楚:空间去哪了?什么文件最大?什么服务在写?有没有被删除但仍占用空间的文件?
5.1 df与du的组合排查套路
第一步看整体利用率:
bash复制df -h
如果某个挂载点满了(比如/data 100%),需要找到具体的大文件。du是标准工具:
bash复制du -sh /data/*
这样能列出/data目录下每个子目录或文件的大小,逐层往下找:
bash复制du -h --max-depth=1 /data | sort -rh | head -20
或者用du -sh *反复进入最大目录排查。对于大型文件,用find直接定位:
bash复制find /data -type f -size +1G -exec ls -lh {} \;
这条命令可以列出/data下所有大于1GB的文件,通常很快能抓到元凶,比如大日志、数据库临时文件、备份文件、Docker容器日志。
5.2 看不到但磁盘满了:被删除文件还没释放
这是最常见的诡异情况:df -h显示100%,但du -sh /把所有目录加起来远小于总量,找遍全盘也没有超大文件。原因通常是某个进程正在写入一个大文件,文件被删除了(rm),但进程仍然持有文件句柄,空间没有真正释放。
办法是查看已删除但仍被占用的文件:
bash复制lsof | grep deleted
或者更精简:
bash复制lsof +L1
找到对应的进程PID后,重启该服务或重启进程,空间才会释放。这个坑在日志服务、Tomcat、数据库等场景特别常见,很多刚入行的同事第一次遇到会懵半天。
5.3 inode耗尽:另一个“空间满”
还有一种满,明明df -h还有几十G空闲,但系统提示“No space left on device”。这就是inode满了。inode是用来存文件元数据(权限、位置、时间等)的槽位,一个小文件就要占一个inode,一旦小文件数量爆炸,就算磁盘容量还剩一大堆,新文件也建不出来。
排查方法:
bash复制df -i
如果IUsed接近100%,那就跑这段找出哪个目录小文件最多:
bash复制for d in /*; do echo "$d: $(find $d -xdev -type f | wc -l)"; done
或者直接查:
bash复制find / -xdev -type f | wc -l
小文件堆积的常见来源:邮件队列(/var/spool/mail)、session临时文件(/tmp)、应用缓存、循环未清理的cron输出、Docker层文件。解决办法通常是删掉无用的日志和小缓存文件,或者把这类路径迁移到独立分区并调大inode数量(mkfs.ext4 -i 262144,指定多少字节一个inode)。
5.4 定时清理与日志轮转
预防比救火重要。日志轮转用logrotate是标配,配置路径在/etc/logrotate.d/,日志服务如nginx、rsyslog一般安装时就带好配置,但很多自定义应用日志需要自己加。
一个简单示例,比如给自定义应用写日志轮转规则:
text复制/app/logs/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0640 app app
}
含义是每天轮转、保留7份、压缩旧日志、缺失跳过、空文件不轮转、轮转后新建空日志文件并设置权限。写完配置可以用logrotate -d /etc/logrotate.d/app做预演(dry run),确认没有问题。
6. 磁盘性能监控与故障恢复:别等出事才后悔
分区、挂载、LVM都是“静态管理”,生产环境中磁盘性能监控和故障处理同样重要,否则等到IO高到爆、系统卡顿甚至数据损坏,再来排查就非常被动。
6.1 实时IO状态:iostat与iotop
iostat看的是系统级IO统计:
bash复制iostat -x 1 5
常用关注项:
%util:设备忙绿程度,接近100%说明已经接近瓶颈。await:平均IO请求等待时间,越大说明排队越严重。rrqm/s、wrqm/s:合并的读写请求数,数值高说明IO调度的合并效果好。svctm:IO服务时间,新版本里可能显示为aqu-sz等,不同发行版略有差异。
iotop则是查看哪个进程在消耗IO:
bash复制iotop -oP
-o只显示有IO活动的进程,-P直接显示进程而非线程。定位到高IO进程后,再根据业务判断是正常业务峰值还是出现了失控线程,比如全表扫描的SQL、日志刷盘频繁的中间件等。
6.2 磁盘健康检查:smartctl让隐患提前暴露
物理硬盘是有寿命的,尤其是机械盘。提前发现坏道和退化状态能帮你赶在数据完蛋前完成迁移。
bash复制smartctl -H /dev/sda
看健康状态。再看详细属性:
bash复制smartctl -a /dev/sda
重点关注属性值(Attribute)中Reallocated_Sector_Ct(重映射扇区数量)和Current_Pending_Sector(当前待映射扇区)。如果这两项持续上涨,说明盘片已经在物理退化,应当尽快备份并安排更换。SSD/NVMe盘则关注Percentage Used、磨损均衡等指标。
还可以加个定时任务每天巡检健康状态,异常时通过邮件或监控系统告警:
bash复制0 2 * * * /usr/sbin/smartctl -H /dev/sda | grep -q "PASSED" || echo "smart check failed" | mail -s "disk alert" ops@example.com
当然实际环境可以用更专业的监控方案替代,思路是一样的:被动等故障不如主动巡检。
6.3 根分区修复与救援经验
Linux磁盘异常表现为启动卡在/dev/sda1: clean, blocks...不动的,或者直接出现Give root password for maintenance的救援模式。常见诱因是之前突然断电、非正常关机或者fstab写错。
启动时进入不了系统,可以用系统盘或救援介质启动,把原系统盘挂载到救援环境,检查/etc/fstab是否写错,也可以先跑文件系统检查:
bash复制fsck /dev/sda1
如果根分区是xfs,对应的检查命令是xfs_repair:
bash复制xfs_repair /dev/sda2
注意:文件系统检查最好在卸载状态下或救援模式下执行,挂载状态跑fsck很容易造成二次损坏。这个场景下的惨痛教训我见过好多次,建议每次改完分区、格式化、挂载相关配置后,都第一时间做好配置备份,例如把/etc/fstab拷贝成/etc/fstab.bak,不要嫌麻烦,关键时刻能救命。
7. 个人经验总结:磁盘管理最容易翻车的几个环节
这些年处理过的磁盘事故,十次里有八次出在下面这几个环节,单独拎出来再说一次。
第一,盘符错认导致格式化错盘。处理方式我上面提到过,格式化前执行lsblk、blkid双重确认。如果是云服务器,控制台里的盘符信息也要跟系统内对一遍,不要只看云平台显示的盘符就动手,遇到过云平台盘符和系统内顺序不一致的情况。
第二,扩容后文件系统没真正变大。很多人执行完lvextend就以为完事了,但文件系统还停在旧容量,导致可用空间没有变化。记住ext4用resize2fs、xfs用xfs_growfs,顺序不能反,参数也别记混。
第三,删除大文件后空间不释放。确认下lsof | grep deleted,不要急着重启整个服务器,重启所有业务影响面太大,先定位到持有句柄的进程,针对它做重载或重启即可。
第四,/etc/fstab改动后不验证。改完立刻执行mount -a验证,再决定是否重启。别把“改完重启”当作流程终点,正确的是“改完验证、验证通过、再考虑重启”。
最后分享一个日常习惯:我习惯于在每台机器上维护一个/root/disk_notes.txt,把磁盘型号、分区规划、挂载关系、UUID这些信息都记录上。机器多的时候,单靠记忆和lsblk来回看,效率低且容易搞混。这个文件本身不占多少空间,但能让运维和交接省下大量时间。
磁盘管理的核心不是学会某个单一命令,而是建立“设备-分区-文件系统-挂载-容量”的整体链路思维。只要链路中的每个环节都搞明白,配好监控,留好备份,绝大多数磁盘问题都能在萌芽阶段解决掉。
