路线图

存储与磁盘管理

星辉 2026-07-02 阅读 6 min 1,200 字 路线图
存储与磁盘管理 封面

Linux 运维基础 · 第十二章 目标:掌握磁盘查看、分区、挂载、LVM 扩容的完整操作


1. 概述#

磁盘是运维不可回避的话题。日志撑爆磁盘、数据库需要扩容、新磁盘需要挂载——这些场景在每个运维的职业生涯中反复出现。

本章从"看"开始,到"扩容"结束,覆盖 df/du/lsblk/fdisk/mount/LVM 全链路。


2. 查看空间#

2.1 df — 文件系统级别#

bash
df -h                            # 人类可读格式
df -hT                           # 同时显示文件系统类型
df -i                            # 查看 inode 使用情况(小文件太多时关注)
df -h / /data /var               # 只看指定目录所在文件系统
bash
# 典型输出
df -h
# Filesystem      Size  Used Avail Use% Mounted on
# /dev/sda1        50G   30G   18G  63% /
# /dev/sdb1       100G   75G   25G  75% /data
# tmpfs           7.8G     0  7.8G   0% /dev/shm
# tmpfs           1.6G  1.1M  1.6G   1% /run

# 重点关注
# Use% 接近 100%  → 告警
# Avail 持续减少  → 趋势恶化,需排查

坑:df 显示还有空间,写文件却报 No space left on device 大概率是 inode 耗尽(小文件太多,如 session/缓存/邮件队列把 inode 用光了)。 df -h 看的是块空间df -i 才看 inode:

bash
df -i                            # IUse% 到 100% 就是 inode 满了
# Filesystem   Inodes  IUsed  IFree IUse% Mounted on
# /dev/sda1   3.2M     3.2M    0    100% /       ← 块没满,inode 满了

# 定位哪个目录小文件最多
for d in /var/*; do echo "$(find "$d" 2>/dev/null | wc -l) $d"; done | sort -rn | head

解决:删掉海量小文件(如清缓存队列),或重建文件系统时调大 inode 密度(mkfs.ext4 -N)。 注意:xfs 的 inode 是动态分配的,通常不会像 ext4 那样固定耗尽。

2.2 du — 目录级别#

bash
du -sh *                         # 当前目录下每个文件/目录的总大小
du -sh /* 2>/dev/null            # 根目录下一级各占多少(忽略错误)
du -sh /home                     # 看 /home 目录总大小

# 找大户
du -sh /* 2>/dev/null | sort -rh | head -10   # 磁盘谁占最多

# 深入排查
du -h --max-depth=1 /var/log/    # 只看一层深度
du -h --max-depth=1 /data/ | sort -rh | head

# 找大文件
find / -type f -size +100M -exec ls -lh {} \; 2>/dev/null

2.3 df vs du 不一致#

bash
# df 显示 80G,du 加起来才 50G——30G 去哪了?
# 答案:见第 02 章"删文件的本质"
# 有进程持有已删除文件的句柄

lsof +L1 | awk '{print $1, $7}' | sort -nrk2 | head
# 找出"幽灵文件",重启对应进程即可释放

3. 查看块设备#

3.1 lsblk — 磁盘/分区树#

bash
lsblk                            # 树形显示所有块设备
lsblk -f                         # 同时显示文件系统类型和 UUID
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE   # 自定义列

# 典型输出
# NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
# sda      8:0    0   50G  0 disk
# ├─sda1   8:1    0   49G  0 part /
# └─sda2   8:2    0    1G  0 part [SWAP]
# sdb      8:16   0  100G  0 disk
# └─sdb1   8:17   0  100G  0 part /data

3.2 fdisk — 分区表#

bash
fdisk -l                         # 列出所有磁盘的分区表
fdisk -l /dev/sdb                # 只看某块磁盘

# fdisk 交互式分区
# fdisk /dev/sdc                 # 进入交互模式
# m = 帮助, n = 新建分区, d = 删除分区
# w = 写入分区表并退出, q = 不保存退出

3.3 其他查看命令#

bash
blkid                            # 查看块设备的 UUID 和文件系统类型
parted -l                        # 更现代的分区查看工具(支持 GPT)
lsscsi                           # 查看 SCSI 设备
ls -la /dev/disk/by-uuid/        # 按 UUID 查看磁盘
ls -la /dev/disk/by-id/          # 按设备 ID 查看

4. 挂载(mount)#

4.1 mount 基础#

bash
# 查看当前挂载
mount | column -t                 # 格式化输出
findmnt                          # 树形显示挂载关系

# 挂载
mount /dev/sdb1 /data            # 挂载分区到目录
mount -t ext4 /dev/sdb1 /data    # 指定文件系统类型
mount -o ro /dev/sdb1 /data      # 只读挂载

# 卸载
umount /data                     # 按挂载点卸载
umount /dev/sdb1                 # 按设备名卸载

# 如果 umount 提示 target is busy
umount -l /data                  # lazy unmount,立即从文件系统树中移除
fuser -m /data                   # 查看谁在用这个挂载点
lsof /data                       # 查看哪些进程打开了文件

4.2 /etc/fstab — 开机自动挂载#

bash
cat /etc/fstab
# <file system>  <mount point>  <type>  <options>  <dump>  <pass>
# /dev/sdb1      /data          ext4    defaults   0       2
# UUID=abc...    /backup        xfs     defaults   0       0

# 字段说明
# 1. 设备: /dev/sdb1 或 UUID=xxx 或 LABEL=xxx
# 2. 挂载点
# 3. 文件系统类型: ext4/xfs/...
# 4. 挂载选项: defaults,noatime,nofail ...
# 5. dump(备份标记,0=不备份)
# 6. pass(开机 fsck 检查顺序,0=不检查,1=根分区,2=其他)
bash
# 添加 fstab 条目后验证
mount -a                         # 测试挂载(不会覆盖已有挂载)

# 常用选项
# defaults    = rw,suid,dev,exec,auto,nouser,async
# nofail      = 设备不存在时不报错(对外部存储很重要)
# noatime     = 不更新文件访问时间(减少磁盘 I/O)
# _netdev     = 网络设备,等网络就绪再挂载(NFS/iSCSI)

4.3 实战:挂载新磁盘#

bash
# Step 1:查看新磁盘
lsblk
# sdc      8:32   0  200G  0 disk    ← 新磁盘

# Step 2:分区(如果不需要可跳过,直接格式化整盘)
fdisk /dev/sdc
# n → 新建分区 → 一路回车(用全部空间)→ w

# Step 3:格式化
mkfs.ext4 /dev/sdc1              # ext4
# 或
mkfs.xfs /dev/sdc1               # xfs

# Step 4:创建挂载点
mkdir -p /data

# Step 5:挂载
mount /dev/sdc1 /data

# Step 6:自动挂载
blkid /dev/sdc1                  # 获取 UUID
echo "UUID=xxx-xxx-xxx  /data  ext4  defaults  0  2" >> /etc/fstab
mount -a                         # 验证

5. LVM 基础#

LVM(Logical Volume Manager)在物理磁盘之上加了一层抽象,让你能在线扩容而无需卸载文件系统。

5.1 三层结构#

text
PV (Physical Volume)  物理卷    ← 物理分区或整盘
  └── VG (Volume Group) 卷组   ← 多个 PV 组合成池
        └── LV (Logical Volume) 逻辑卷   ← 从 VG 中分配的空间,挂载使用

一个类比:PV 是硬盘,VG 是硬盘阵列柜,LV 是从柜子里划出来的分区。

5.2 查看 LVM#

bash
pvdisplay                        # 查看物理卷(或 pvs,简洁版)
vgdisplay                        # 查看卷组(或 vgs)
lvdisplay                        # 查看逻辑卷(或 lvs)

5.3 扩容逻辑卷#

bash
# 场景:/data 分区快满了,从 VG 还有 50G 空闲,扩容 LV

# Step 1:确认当前大小
df -h /data

# Step 2:LV 扩容
lvextend -L +20G /dev/mapper/vg_data-lv_data
# 或扩展到 100% 的 VG 剩余空间
lvextend -l +100%FREE /dev/mapper/vg_data-lv_data

# Step 3:文件系统扩容(LV 变大了,文件系统还不知道,得单独扩)
# ext4 —— 认设备路径:
resize2fs /dev/mapper/vg_data-lv_data
# xfs   —— 认挂载点,且文件系统必须处于挂载状态:
xfs_growfs /data

# Step 4:确认
df -h /data

必记的文件系统差异(扩缩容规则)

文件系统扩容命令在线扩容缩小
ext4resize2fs <设备>支持支持,但必须先 umount 离线操作,且需先缩文件系统再缩 LV
xfsxfs_growfs <挂载点>支持(必须挂载着扩)不支持!只能扩不能缩
  • xfs 无法缩小是最常见的坑:分区规划过大想收回空间时才发现退不回来, 唯一办法是备份数据 → 重建更小的文件系统 → 恢复。规划 xfs 时宁可留小点。
  • 默认文件系统:RHEL/Rocky/Alma 系默认 xfs,Debian/Ubuntu 系默认 ext4。 建新盘前先想清楚将来会不会需要缩容,需要缩就别用 xfs。
  • 命令别记混:resize2fs 收/放 ext4、认设备名xfs_growfs 只放 xfs、认挂载点

5.4 创建 LVM(从零开始)#

bash
# Step 1:创建 PV
pvcreate /dev/sdc1

# Step 2:创建 VG
vgcreate vg_data /dev/sdc1

# Step 3:创建 LV
lvcreate -L 50G -n lv_data vg_data

# Step 4:格式化
mkfs.ext4 /dev/mapper/vg_data-lv_data

# Step 5:挂载
mkdir -p /data
mount /dev/mapper/vg_data-lv_data /data

echo "/dev/mapper/vg_data-lv_data /data ext4 defaults 0 2" >> /etc/fstab

6. Swap#

6.1 查看#

bash
free -h                          # 看 Swap 大小和使用
swapon --show                    # 查看所有交换空间

6.2 增加 Swap#

bash
# 场景:物理内存不够,临时加 4G Swap

# Step 1:创建 swap 文件
dd if=/dev/zero of=/swapfile bs=1G count=4
# 4G 文件

# Step 2:设置权限
chmod 600 /swapfile               # 安全要求

# Step 3:格式化为 swap
mkswap /swapfile

# Step 4:激活
swapon /swapfile

# Step 5:开机自动激活
echo "/swapfile  none  swap  sw  0  0" >> /etc/fstab

# 验证
free -h
swapon --show

7. 文件系统修复#

bash
# fsck:文件系统检查与修复
# 使用前必须 umount!

umount /dev/sdb1
fsck -y /dev/sdb1                 # -y 自动回答 yes
fsck -n /dev/sdb1                 # -n 只检查不修复(安全预览)

# 注意:fsck 只能修复元数据层面的问题,硬件坏道无法修复

8. 实战#

实战 1:磁盘谁占最多#

bash
# 快速定位
du -sh /* 2>/dev/null | sort -rh | head -10

# 如果发现 /var 巨大,深入查
du -h --max-depth=1 /var/ | sort -rh | head -10

# 发现 /var/log 很大
du -h --max-depth=1 /var/log/ | sort -rh | head -10

# 发现 nginx 日志 20G
ls -lh /var/log/nginx/
# 马上清理
find /var/log/nginx -name "*.log" -mtime +30 -delete
# 或压缩留存
find /var/log/nginx -name "*.log" -mtime +30 -exec gzip {} \;

实战 2:根分区扩容#

bash
# 场景:云服务器购买了更大磁盘,根分区还是老大小

# Step 1:确认新大小
lsblk
# sda 从 50G 变成了 100G

# Step 2:扩展分区
growpart /dev/sda 1                # 对根分区所在的分区号(growpart 属 cloud-utils-growpart 包)
# 注意 growpart 后面是【空格】分区号,不是 /dev/sda1

# 如果是 LVM 根分区(Rocky/Alma 9 默认 VG 名多为 rl / almalinux,用 lvs 确认真实名字)
pvresize /dev/sda1
lvextend -r -l +100%FREE /dev/mapper/rl-root
# -r 参数自动调用 resize2fs(ext4)/xfs_growfs(xfs),省掉手动扩文件系统那步

# Step 3:验证
df -h /

实战 3:应急 Swap#

bash
# 场景:数据库 OOM,内存不够,临时加 swap 扛住

dd if=/dev/zero of=/swapfile bs=1G count=8 status=progress
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

# 确认生效
free -h | grep Swap

# 持久化
echo "/swapfile none swap sw 0 0" >> /etc/fstab

# 通知团队,安排扩容内存

9. 小结#

知识点一句话记忆
df文件系统级别,df -h 看块空间,df -i 看 inode
inode 耗尽块没满却报 No space → df -i 查 IUse%(小文件太多)
du目录级别,du -sh /* 找大户
lsblk树形看磁盘和分区
mountmount /dev/sdb1 /data 挂载,/etc/fstab 开机自动挂载
LVMPV→VG→LV 三层,lvextend + resize2fs(ext4) / xfs_growfs(xfs) 在线扩容
xfs vs ext4xfs 只能扩不能缩;ext4 可扩可缩(缩要离线);RHEL 系默认 xfs、Debian 系默认 ext4
df vs du 不一致进程持有已删除文件——lsof | grep deleted
Swapdd + mkswap + swapon 三步创建

上一章:十一、网络诊断工具 下一章:十三、服务管理 systemd