Appearance
磁盘管理
磁盘扩容、挂载、空间告警排查,这些活儿运维天天干。但磁盘这块概念多、层级多——设备、分区、文件系统、挂载点、LVM、RAID,一层套一层,不把这些关系搞清楚,排查"磁盘满了""扩容没生效""重启后挂载丢了"这类问题就会一团乱。这篇按从底层到上层的顺序把这些概念串起来。
一、磁盘、分区、文件系统、挂载点
排查磁盘问题时,有四个概念特别容易混,先厘清:
| 概念 | 是什么 | 例子 |
|---|---|---|
| 设备 | 系统识别到的物理或虚拟磁盘 | /dev/sdb |
| 分区 | 磁盘上划分出来的一段独立区域 | /dev/sdb1 |
| 文件系统 | 组织数据的方式,决定文件怎么存怎么查 | xfs、ext4 |
| 挂载点 | 文件系统接到目录树里的入口 | /data、/mnt/backup |
排查磁盘问题的顺序就是从这四层从下往上走:系统有没有识别到盘 → 分区表对不对 → 文件系统建了没 → 挂载了没。任何一层断了,上面的都白搭。
查看块设备和挂载关系:
bash
lsblk # 块设备树:磁盘→分区→挂载点,最直观的总览
blkid # 看 UUID 和文件系统类型
df -h # 看各挂载点的空间使用情况
df -i # 看 inode 使用情况lsblk 是磁盘总览的最好工具,一眼看清设备、分区、挂载点三层关系。df -h 看空间,df -i 看 inode——有个经典坑:磁盘空间明明没满(df -h 还有余量)却写不进文件,十有八九是 inode 用完了(df -i 那一列 100%)。通常是某个目录里塞了几百万个小文件,每个文件占一个 inode,空间没占多少但 inode 耗光了。
二、分区
分区表是磁盘上的"目录",记录每个分区从哪到哪。老格式叫 MBR(DOS),只能支持 2TB 以下磁盘、最多 4 个主分区;现代格式叫 GPT,支持大磁盘、最多 128 个分区、还有备份分区表(主分区表坏了能恢复)。新盘现在基本都用 GPT。
bash
fdisk -l # 查看所有磁盘分区(MBR 和 GPT 都能看)
parted -l # 更详细,操作 GPT 也更方便给新磁盘分区的流程,以 parted 为例:
bash
lsblk # 先看磁盘设备名,确认是 /dev/sdb
parted /dev/sdb # 进入 parted 交互模式parted 交互模式里几个常用命令:mklabel gpt 创建 GPT 分区表(注意这步会清空原有分区!)、mkpart primary 0% 100% 创建一个占满整盘的主分区、print 看当前分区表、quit 退出。
分区完成之后通知内核重新读分区表:
bash
partprobe /dev/sdb # 通知内核重新扫描分区
lsblk # 确认 /dev/sdb1 出现了云环境有个坑:有些云主机的设备名重启之后可能变,比如这次是 /dev/sdb,重启后变成 /dev/sdc。所以挂载的时候别依赖设备名,用 UUID——UUID 是文件系统格式化时生成的,不会变。这就是为什么 fstab 里都推荐写 UUID 而不是 /dev/sdb1。
三、格式化
在分区上创建文件系统:
bash
mkfs.xfs /dev/sdb1
mkfs.ext4 /dev/sdb1XFS 和 ext4 是两个主流选择。简单说:RHEL 7+ 默认用 XFS,适合大文件大数据;ext4 是通用选择,Ubuntu 上常见。两者都支持在线扩容,但都不支持在线缩容(XFS 压根不支持缩,ext4 要先卸载)。
格式化会清空分区上原有数据,这是不可逆的。所以生产环境执行 mkfs 之前,一定要再确认一遍设备和挂载情况:
bash
lsblk -f # 看当前文件系统类型,确认这块盘不是正在用的
mount | grep sdb # 确认这块盘没被挂载使用格式化错盘导致数据全没的事故真实发生过——把正在跑业务的盘 mkfs 了,数据直接归零。多确认两秒,值得。
四、挂载与 fstab
挂载就是把文件系统接到目录树的某个位置:
bash
mkdir -p /data
mount /dev/sdb1 /data
df -h /data手动 mount 重启后就失效了,持久化挂载要写进 /etc/fstab。fstab 里推荐用 UUID 指定设备:
bash
blkid /dev/sdb1 # 获取这块盘的 UUID/etc/fstab 一行长这样:
UUID=xxxx-xxxx /data xfs defaults 0 0六列从左到右:设备标识(用 UUID=xxxx-xxxx,比设备路径可靠)、挂载点(/data)、文件系统类型(xfs)、挂载选项(defaults 是一组默认参数)、dump 备份标志(通常 0)、fsck 检查顺序(根分区是 1,其他是 2,0 表示跳过)。
写完 fstab 之后,务必先用 mount -a 测试一遍——它会按 fstab 把所有未挂载的条目挂载一遍。如果 fstab 有语法错误,mount -a 会立刻报错,你当场就能改;但如果直接重启,fstab 写错可能导致系统进 emergency mode(紧急模式),连正常登录都难,得接控制台修。这一步测试值千金。
五、SWAP
SWAP 是磁盘上划出来的一块区域,当物理内存不够用的时候,内核会把不活跃的内存页换到 SWAP 上,腾出物理内存给更需要的进程。本质是用磁盘当"溢出的内存",速度比物理内存慢几个数量级,所以只是应急,不是常态方案。
bash
free -h # 看内存和 SWAP 使用量
swapon --show # 看当前 SWAP 设备创建 SWAP 文件:
bash
fallocate -l 2G /swapfile # 创建 2G 大小的文件
chmod 600 /swapfile # SWAP 文件权限要严格(只 root 可读写)
mkswap /swapfile # 格式化为 SWAP
swapon /swapfile # 启用写入 /etc/fstab 永久生效:
/swapfile none swap sw 0 0数据库服务器(MySQL、PostgreSQL、Redis)通常不希望依赖 SWAP——数据库一旦开始大量换出到 SWAP,性能会断崖式下跌,本来毫秒级的查询变成秒级。偶尔换出一点点是正常的,但如果看到 SWAP 在频繁大量活动(thrashing),说明物理内存严重不足,得加内存或者优化配置,而不是放任它用 SWAP。
六、LVM
LVM(Logical Volume Manager)在物理磁盘和文件系统之间加了一层抽象,最大的好处是能动态扩容——不用停服务、不用卸载文件系统,就能给逻辑卷加空间。云环境之外(云盘本身能在线扩容)的物理服务器,LVM 几乎是标配。
LVM 是三层结构:PV(物理卷)是把磁盘分区初始化成 LVM 能管的;VG(卷组)是多个 PV 组成的存储池;LV(逻辑卷)是从 VG 里划出来的逻辑空间,文件系统就建在 LV 上。
创建流程:
bash
pvcreate /dev/sdb1 # 把分区初始化成物理卷
vgcreate vg_data /dev/sdb1 # 创建卷组 vg_data
lvcreate -n lv_data -l 100%FREE vg_data # 用全部剩余空间建逻辑卷
mkfs.xfs /dev/vg_data/lv_data # 在逻辑卷上建文件系统扩容流程(加了新磁盘之后):
bash
pvcreate /dev/sdc1 # 新磁盘初始化成 PV
vgextend vg_data /dev/sdc1 # 把新 PV 加进卷组(VG 变大)
lvextend -r -l +100%FREE /dev/vg_data/lv_data # 扩 LV 并同步扩文件系统注意 -r 参数——它会自动扩展文件系统(内部调 xfs_growfs 或 resize2fs),不用你手动再跑一遍扩容命令。忘了 -r 的话,逻辑卷是大了,但文件系统还是原来的大小,白扩。
查看 LVM 状态:pvs 看物理卷、vgs 看卷组、lvs 看逻辑卷。
LVM 扩容方便,但缩容麻烦——前面说了 XFS 不支持在线缩容,ext4 也要先卸载。所以规划存储的时候,"以后不够再缩"不是个好假设,空间宁可一开始规划宽松点。
七、RAID
RAID 用多块磁盘组合成逻辑存储,提供性能提升或冗余保护。常见级别:
| 级别 | 特点 | 适用场景 |
|---|---|---|
| RAID 0 | 条带化,性能好但无冗余,坏一块盘数据全丢 | 不重要、追求性能的数据 |
| RAID 1 | 镜像,容量减半,坏一块还能继续跑 | 系统盘、重要数据 |
| RAID 5 | 奇偶校验,可坏 1 块盘,空间利用率高 | 一般业务存储 |
| RAID 10 | 镜像+条带,性能好且冗余,最少 4 块盘 | 高性能高可靠场景 |
Linux 软件 RAID 用 mdadm 管理:
bash
cat /proc/mdstat # 看当前 RAID 状态(哪几块盘、是否降级)
mdadm --detail /dev/md0 # 看指定 RAID 设备的详细信息云环境里基本不需要自己搞 RAID——云平台的底层存储通常已经做了冗余(多副本、分布式存储),你在云主机上看到的一块"云盘"背后已经是高可靠的。再套一层软件 RAID 没什么额外收益,反而增加复杂度。云盘的可靠性保障和 RAID 解决的物理盘故障,根本不是一个层面的事。
八、排查空间占用
磁盘告警的排查分两步:先定位是哪个目录在吃空间,再找到具体的大文件。
bash
df -h # 确认哪个分区满了
du -sh /* # 根目录下各目录的占用,看哪个大
du -sh /var/* # 逐层深入
find /var -type f -size +1G -ls # 直接列出大于 1G 的文件还有一种很迷惑的情况:文件删了,但空间没释放。明明 rm 掉了一个几十 G 的日志文件,df -h 显示空间一点没少。原因是还有进程持有这个文件的文件描述符——文件从目录里消失了,但 inode 没释放,空间还占着。排查用:
bash
lsof | grep deleted输出里带 (deleted) 标记的,就是这种"已删除但还被占着"的文件。解决办法:重启那个持有文件的进程(让文件描述符释放),或者让进程重新打开日志文件(比如 systemctl reload nginx,nginx 会重新打开日志文件,旧的就被释放了)。