从“看见一块盘”到“安全管理一条存储链”

上一篇《网络配置》讲的是数据如何离开主机、经过路由和网络到达其他系统;本篇回到主机内部,讨论数据如何从应用写入文件系统,再经过逻辑卷、设备映射和块设备落到物理盘、虚拟盘或云盘。

磁盘管理的危险不在于命令难,而在于同一条命令作用于错误设备时往往不可逆。mkfswipefspvcreateparteddd 和某些修复工具都可能在数秒内破坏元数据。生产操作必须先建立存储栈心智模型,确认设备身份、数据归属、依赖关系、备份和回滚边界,再执行变更。

本文采用“存储栈原理 + 配置 walkthrough + 扩容迁移 + 故障排查 runbook”的结构。示例以常见 util-linux、LVM2、ext4 和 XFS 工具为主。不同发行版、内核、文件系统和存储控制器版本可能存在差异,实施前应使用本机 man--help 和发行版官方文档核对。

读完本文后,你应该能够:

  1. 使用 lsblkblkidfindmntudevadm/sys 识别设备及其关系。
  2. 区分磁盘、分区、软件 RAID、LUKS、LVM、文件系统和挂载点。
  3. 安全创建 GPT 分区、LVM 逻辑卷和 ext4/XFS 文件系统。
  4. 正确编写并验证 /etc/fstab
  5. 扩展虚拟盘、分区、PV、LV 和文件系统。
  6. 判断空间满、inode 满、I/O 延迟、只读文件系统、设备丢失和挂载失败。
  7. 理解在线扩容、离线检查、缩容和设备替换的风险边界。

1. Linux 存储不是一块盘,而是多层对象

应用通常只看到路径,例如 /var/lib/postgresql/data。但路径下面可能经过多个层次:

text
应用目录
  -> 挂载点
  -> ext4 / XFS
  -> LVM Logical Volume
  -> LVM Volume Group
  -> LVM Physical Volume
  -> GPT 分区
  -> 虚拟磁盘 / 云盘 / SAN LUN / 本地 SSD

还可能在中间加入 LUKS 加密、mdadm 软件 RAID、多路径设备或设备映射。排障和变更时,必须先知道当前主机实际使用了哪些层。

图中把应用到磁盘的层次串起来。扩容、迁移和故障修复必须逐层推进,不能看到 /dev/sdb 就假定它直接承载某个目录。

1.1 常见设备命名

设备形式 常见含义
/dev/sda/dev/sdb SCSI/SATA/USB/虚拟块设备的传统名称
/dev/vda VirtIO 虚拟磁盘
/dev/nvme0n1 NVMe 设备
/dev/nvme0n1p1 NVMe 第一个分区
/dev/md0 mdadm 软件 RAID
/dev/mapper/cryptdata device-mapper/LUKS 映射
/dev/mapper/vg_data-lv_app LVM 逻辑卷映射
/dev/dm-0 device-mapper 内核编号,不适合作为持久配置名称

设备名并不总是稳定。新增控制器、调整虚拟机硬件或改变发现顺序后,/dev/sdb 可能变成 /dev/sdc。持久挂载优先使用文件系统 UUID、LVM 路径或经过验证的稳定 by-id 路径。

1.2 先用 lsblk 建立拓扑

lsblk 来自 util-linux,用于列出块设备。建议显式指定输出列,避免脚本依赖不同版本的默认列。

bash
lsblk -e 7 \
  -o NAME,KNAME,PATH,TYPE,SIZE,FSTYPE,FSVER,LABEL,UUID,MOUNTPOINTS,MODEL,SERIAL

其中:

  • NAME 展示树形名称;
  • KNAME 是内核设备名;
  • TYPE 可区分 disk、part、lvm、crypt、raid;
  • FSTYPEUUID 来自文件系统或签名探测;
  • MOUNTPOINTS 展示一个设备可能对应的多个挂载点;
  • MODELSERIAL 有助于确认硬件或虚拟盘身份。

设备刚热添加后,udev 信息可能尚未完全就绪。自动化脚本中可以在读取前执行:

bash
udevadm settle
lsblk --json -o NAME,PATH,TYPE,SIZE,FSTYPE,UUID,MOUNTPOINTS

结构化输出比解析对齐文本更可靠。

1.3 用 findmnt 从目录反查设备

如果问题从目录开始,例如 /var 满了,应优先从挂载点反查:

bash
findmnt /var
findmnt -T /var/lib/app
findmnt -no SOURCE,FSTYPE,OPTIONS,TARGET /var

再沿设备向下查看:

bash
lsblk -f
lsblk -s /dev/mapper/vg_system-lv_var
lvs -a -o +devices
pvs -o pv_name,vg_name,pv_size,pv_free

lsblk -s 以反向依赖顺序显示设备链,适合从 LV 或文件系统回溯到底层磁盘。

1.4 不要把 df 和 du 混为一谈

df 从文件系统视角统计已用块和可用块;du 遍历目录项统计可见文件大小。两者不一致时,可能存在:

  • 文件已删除但仍被进程打开;
  • 目录被另一个文件系统覆盖挂载;
  • 稀疏文件的逻辑大小与实际占用不同;
  • 快照、保留块、元数据或文件系统开销;
  • 权限导致 du 无法遍历所有目录。

基础检查:

bash
df -hT
df -ih
du -xhd1 /var 2>/dev/null | sort -h
lsof +L1

df -i 用于检查 inode。大量小文件可能在容量仍有剩余时耗尽 inode,表现为“设备上没有空间”。

2. 变更前先做设备身份确认

磁盘事故中最常见的错误不是命令失败,而是命令成功作用在错误设备上。生产变更前应保存证据。

bash
audit_dir="$HOME/storage-audit-$(date +%F-%H%M%S)"
mkdir -p "$audit_dir"

lsblk -e 7 -o NAME,KNAME,PATH,TYPE,SIZE,FSTYPE,LABEL,UUID,MOUNTPOINTS,MODEL,SERIAL \
  > "$audit_dir/lsblk.txt"
blkid > "$audit_dir/blkid.txt" 2>&1
findmnt --real > "$audit_dir/findmnt.txt"
df -hT > "$audit_dir/df-hT.txt"
df -ih > "$audit_dir/df-inode.txt"
pvs > "$audit_dir/pvs.txt" 2>&1
vgs > "$audit_dir/vgs.txt" 2>&1
lvs -a -o +devices > "$audit_dir/lvs.txt" 2>&1
cat /etc/fstab > "$audit_dir/fstab.txt"
dmesg -T | tail -300 > "$audit_dir/dmesg-tail.txt"

然后回答:

  1. 目标设备的序列号、容量、总线和云平台磁盘 ID 是什么?
  2. 设备是否已有分区、文件系统、LVM、RAID 或 LUKS 签名?
  3. 是否被挂载、被进程打开、作为 swap 或作为 RAID/LVM 成员?
  4. 数据是否有备份,最近一次恢复是否验证?
  5. 变更失败时,能回滚到哪一层?

检查签名时可使用只读探测:

bash
sudo wipefs --no-act /dev/sdb
sudo blkid -p /dev/sdb

不要把 wipefs 不带 --no-act 用作“查看命令”。删除签名属于破坏性操作。

3. 分区:GPT 是现代服务器的默认选择

分区表描述磁盘上的分区边界。现代服务器通常优先使用 GPT,原因包括支持大容量磁盘、分区数量更灵活,并保留主分区表和备份信息。MBR 仍可能出现在旧系统、兼容环境和某些启动场景中。

3.1 查看分区表

bash
sudo fdisk -l /dev/sdb
sudo parted /dev/sdb print
sudo sfdisk --dump /dev/sdb

变更前可备份分区布局:

bash
sudo sfdisk --dump /dev/sdb > "$audit_dir/sdb-partition-table.sfdisk"

对于 GPT,也可按环境使用 sgdisk --backup。恢复工具必须提前验证,不要在事故现场第一次使用。

3.2 创建新 GPT 分区

以下假设 /dev/sdb 是已确认的新空盘,且不存在需要保留的数据:

bash
sudo parted -s /dev/sdb mklabel gpt
sudo parted -s /dev/sdb mkpart primary 1MiB 100%
sudo partprobe /dev/sdb
udevadm settle
lsblk -f /dev/sdb

保留 1 MiB 起始对齐通常适用于现代存储。执行前必须再次检查设备路径。

如果分区用于 LVM,可设置对应标志或分区类型;但 LVM 能直接使用整盘,也能使用分区。企业应统一规范,避免同一环境一部分整盘做 PV、一部分分区做 PV,增加识别难度。

3.3 扩展分区的边界

虚拟化或云平台扩展底层磁盘后,Linux 可能先看到新的磁盘容量,但分区仍保持原大小。典型流程是:

text
扩展云盘/虚拟盘
  -> 让内核重新识别容量
  -> 扩展目标分区
  -> 扩展 PV
  -> 扩展 LV
  -> 扩展文件系统

每一步都要验证。不能看到云控制台容量变大,就直接执行 resize2fs

重新识别方式取决于设备类型和平台。可以先比较:

bash
lsblk
sudo blockdev --getsize64 /dev/sdb
cat /sys/class/block/sdb/size

某些环境需要重新扫描 SCSI 总线、控制器或重启实例。具体方法应遵循平台官方文档,避免对错误 host 扫描路径。

4. LVM:用 PV、VG、LV 解耦物理容量和文件系统

LVM 将底层块设备抽象为 Physical Volume,将多个 PV 汇聚成 Volume Group,再从 VG 分配 Logical Volume。它的价值是容量池化、在线扩展、设备迁移和灵活命名,而不是替代备份。

4.1 观察 LVM 状态

bash
sudo pvs -o pv_name,vg_name,pv_size,pv_free,pv_uuid
sudo vgs -o vg_name,vg_size,vg_free,pv_count,lv_count
sudo lvs -a -o lv_name,vg_name,lv_size,lv_attr,segtype,devices

lvs -o +devices 非常重要,它能显示 LV 的数据实际位于哪些 PV 上。执行 pvmove、移除磁盘或排查丢盘时,不能只看 LV 名称。

4.2 创建 PV、VG 和 LV

以下假设 /dev/sdb1 是已确认、无需保留数据的新分区:

bash
sudo pvcreate /dev/sdb1
sudo vgcreate vg_data /dev/sdb1
sudo lvcreate -L 100G -n lv_app vg_data

验证:

bash
sudo pvs
sudo vgs
sudo lvs -a -o +devices
lsblk -f

生产环境命名应体现用途,而不是只用 vg0/lv0。例如 vg_data/lv_postgresvg_logs/lv_audit 更容易审计。但命名也不应包含频繁变化的服务器名或项目临时代号。

4.3 VG 不等于冗余

把两块磁盘加入同一个 VG,只是汇聚容量,不自动提供 RAID 冗余。如果任一 PV 丢失,而 LV 的 extents 分布在该 PV 上,LV 可能部分或全部不可用。

需要冗余时,应在底层存储、硬件 RAID、mdadm、LVM RAID、SAN 或云盘复制层明确设计。不要把“VG 有两块盘”误认为“双盘保护”。

4.4 LVM 元数据备份

LVM 通常会在 /etc/lvm/backup/etc/lvm/archive 保存元数据文本副本。重要变更前可以显式备份:

bash
sudo vgcfgbackup vg_data
sudo ls -l /etc/lvm/backup /etc/lvm/archive

元数据备份不能恢复文件数据,但在某些 VG 元数据损坏场景中非常关键。应把这些文件纳入系统配置备份。

5. 创建文件系统:格式化之前要最后确认一次

mkfs 会创建新文件系统并覆盖关键元数据。执行前至少运行:

bash
lsblk -f /dev/mapper/vg_data-lv_app
findmnt -S /dev/mapper/vg_data-lv_app
sudo wipefs --no-act /dev/mapper/vg_data-lv_app

确认目标未挂载、无现有数据、无业务依赖。

5.1 ext4

bash
sudo mkfs.ext4 -L appdata /dev/mapper/vg_data-lv_app

ext4 支持在线扩容。缩容通常要求离线,并且必须先缩文件系统再缩块设备;顺序错误会直接破坏数据。生产环境中,与其在线上做 ext4 缩容,通常更稳妥的是创建新卷、迁移数据、切换挂载并保留回滚。

5.2 XFS

bash
sudo mkfs.xfs -L appdata /dev/mapper/vg_data-lv_app

XFS 支持挂载状态下扩容,常用 xfs_growfs。传统 XFS 运维实践中不支持缩小现有文件系统,因此缩容通常采用新建较小文件系统、复制数据和切换挂载的方式。

5.3 选择 ext4 还是 XFS

维度 ext4 XFS
通用性 广泛支持,适合多数 Linux 工作负载 企业服务器和大文件/高并发场景常见
在线扩容 支持 支持
缩容 可离线缩容,但风险高 通常不支持原地缩容
修复工具 e2fsck xfs_repair
配额 支持 支持,需按挂载参数和发行版配置

文件系统选择不能只依据“哪个快”。还要考虑发行版默认、运维经验、备份工具、快照、恢复流程、工作负载和厂商支持。

6. 挂载与 fstab:持久配置必须先验证

创建挂载点:

bash
sudo install -d -o root -g root -m 0755 /data/app

临时挂载:

bash
sudo mount /dev/mapper/vg_data-lv_app /data/app
findmnt /data/app
df -hT /data/app

写入测试前先确认目录原来没有被其他数据占用。挂载会遮住挂载点目录原有内容,卸载后原内容才会重新出现。

6.1 使用 UUID

查询 UUID:

bash
sudo blkid /dev/mapper/vg_data-lv_app

/etc/fstab 示例:

fstab
UUID=<filesystem-uuid>  /data/app  xfs  defaults,noatime  0  0

ext4 示例:

fstab
UUID=<filesystem-uuid>  /data/app  ext4  defaults,noatime  0  2

最后两个字段分别与 dump 和 fsck 顺序有关。根文件系统通常使用 1,其他 ext 系列文件系统常用 2;XFS 常用 0。应遵循发行版规范,不要机械复制。

6.2 修改 fstab 后不要直接重启验证

先执行:

bash
sudo findmnt --verify --verbose
sudo systemctl daemon-reload
sudo mount -a
findmnt /data/app

如果 mount -a 报错,应立即修正。错误的 fstab 可能导致启动进入紧急模式。

对于非关键网络或可移除存储,可以考虑 nofailx-systemd.automount、设备超时等选项,但这些选项会改变启动和故障语义。核心业务数据盘不应简单加 nofail 掩盖丢盘。

6.3 权限属于文件系统内容,不属于挂载命令

挂载完成后,根据应用账号设置:

bash
sudo chown appuser:appgroup /data/app
sudo chmod 0750 /data/app

如果卸载后发现权限“变化”,可能是你看到的其实是底层挂载点目录,而不是文件系统根目录。排查时始终用 findmnt -T 确认当前路径属于哪个文件系统。

7. LVM 在线扩容完整 walkthrough

扩容看起来简单,但必须按层次执行。下面假设:

  • 云平台已将 /dev/sdb 从 200 GiB 扩展到 300 GiB;
  • /dev/sdb1 是 LVM PV;
  • VG 为 vg_data
  • LV 为 lv_app
  • 文件系统挂载到 /data/app
LVM 在线扩容流程

图中把扩盘、PV、VG、LV 和文件系统分开。扩容通常可在线完成,但每一层都要确认实际容量和业务状态。

7.1 变更前检查

bash
findmnt /data/app
df -hT /data/app
lsblk -f
pvs
vgs
lvs -a -o +devices

确认备份和恢复点,检查业务是否允许变更,记录当前 I/O 和延迟。

7.2 确认内核看到新磁盘容量

bash
lsblk /dev/sdb
sudo blockdev --getsize64 /dev/sdb

如果容量未变化,应先按虚拟化、云平台或存储厂商文档完成重扫。不要继续扩分区。

7.3 扩展分区

如果 PV 位于第一个分区,可按环境使用 growpartparted 或其他受支持工具。以 growpart 为例:

bash
sudo growpart /dev/sdb 1
sudo partprobe /dev/sdb
udevadm settle
lsblk /dev/sdb

growpart 并非所有系统默认安装,命令行为要以本机帮助和发行版包为准。使用前必须备份分区表。

7.4 扩展 PV

bash
sudo pvresize /dev/sdb1
sudo pvs -o pv_name,pv_size,pv_free,vg_name
sudo vgs

如果 pvresize 后 VG 没有出现预期空闲空间,应停止并检查分区和设备容量,不要直接改 LV。

7.5 扩展 LV

扩展 50 GiB:

bash
sudo lvextend -L +50G /dev/vg_data/lv_app

使用全部剩余空间:

bash
sudo lvextend -l +100%FREE /dev/vg_data/lv_app

验证:

bash
sudo lvs -a -o lv_name,vg_name,lv_size,devices
lsblk

+100%FREE 会消耗 VG 所有剩余空间,可能让后续快照、临时扩容和其他 LV 无空间可用。生产环境通常应保留一定 VG 空闲容量。

7.6 扩展文件系统

ext4:

bash
sudo resize2fs /dev/vg_data/lv_app

XFS 必须针对已挂载路径执行:

bash
sudo xfs_growfs /data/app

验证:

bash
df -hT /data/app
findmnt /data/app
lsblk -f

有些 lvextend 版本支持 -r 调用 fsadm 或文件系统工具同步扩容,例如:

bash
sudo lvextend -r -L +50G /dev/vg_data/lv_app

生产环境使用前应确认发行版支持的文件系统、工具链和日志输出。分步执行虽然多几条命令,但更容易在每层验证。

8. 新增磁盘扩展 VG

如果不是扩原盘,而是新增 /dev/sdc

bash
lsblk -f /dev/sdc
sudo wipefs --no-act /dev/sdc

确认新盘无数据后创建 PV:

bash
sudo pvcreate /dev/sdc
sudo vgextend vg_data /dev/sdc
sudo pvs
sudo vgs

然后按需要扩 LV 和文件系统。

8.1 注意数据分布

新增 PV 后扩展 LV,新的 extents 可能落在新盘上。此后 LV 依赖多块盘,任何一块丢失都可能影响数据。底层是否具备冗余必须明确。

8.2 安全移除 PV

不能直接从系统删除仍承载 extents 的 PV。先看:

bash
sudo pvs -o pv_name,vg_name,pv_size,pv_free,pv_used
sudo lvs -a -o +devices

如果 VG 有其他足够空间,可迁移:

bash
sudo pvmove /dev/sdc
sudo vgreduce vg_data /dev/sdc
sudo pvremove /dev/sdc

pvmove 可能产生大量 I/O,应在变更窗口监控延迟和业务。执行前确认目标 PV 空间、冗余、备份和中断恢复能力。

9. 空间满:先区分容量、inode 和隐藏占用

9.1 容量满

bash
df -hT
du -xhd1 /var | sort -h
du -xhd1 /data | sort -h

-x 避免跨越其他文件系统。定位到大目录后逐层下钻,不要直接在根目录执行无边界的全盘 du 影响业务。

9.2 inode 满

bash
df -ih
find /var/spool/app -xdev -type f -printf '%h\n' 2>/dev/null \
  | sort | uniq -c | sort -n | tail

大量小文件常见于缓存、队列、邮件、临时目录、日志切分和任务失败重试。删除文件前要先确认应用语义,避免破坏队列或状态。

9.3 删除文件仍不释放空间

bash
sudo lsof +L1

如果进程仍持有已删除文件,空间会在文件描述符关闭后释放。优先让应用重新打开日志、执行受支持的 reload,或在窗口内重启服务。不要直接操作 /proc/<pid>/fd 指向的文件,除非有明确的取证和恢复方案。

9.4 日志治理

检查 journal:

bash
journalctl --disk-usage

检查 logrotate:

bash
sudo logrotate -d /etc/logrotate.conf

不要在生产中未经评估直接删除活跃数据库、容器运行时或审计日志。正确做法是确定增长源、保留要求、轮转策略和容量告警。

10. I/O 性能:容量正常也可能很慢

磁盘性能问题需要区分设备延迟、队列、吞吐、文件系统、应用访问模式和底层共享存储争用。

10.1 iostat

安装 sysstat 后可使用:

bash
iostat -xz 1 10

常见观察项包括:

  • r/sw/s:每秒读写请求;
  • rkB/swkB/s:吞吐;
  • await:请求平均等待时间;
  • aqu-sz:平均队列长度;
  • %util:设备忙碌程度。

不能只看 %util。不同设备、NVMe、多队列和虚拟化环境中,指标含义需要结合延迟、吞吐和业务 SLA。高延迟也可能来自 SAN、云盘限速、快照、备份或邻居工作负载。

10.2 pidstat 与进程定位

bash
pidstat -d 1 10
sudo iotop -oPa

工具未安装时,可结合 /proc/<pid>/io、服务指标和应用日志。不要在事故中为了安装工具触发大量包升级。

10.3 云盘和虚拟盘的特殊限制

云盘常将性能与容量、规格、突发额度或实例带宽绑定。虚拟机内部看到的延迟可能来自:

  • 云盘 IOPS/吞吐上限;
  • 实例总存储带宽上限;
  • 突发额度耗尽;
  • 快照或备份任务;
  • 多盘共享控制器;
  • 宿主机或存储网络问题。

排查时要同时查看主机指标和平台侧磁盘指标。

11. 设备健康、内核错误与 SMART

11.1 先看内核日志

bash
dmesg -T | grep -Ei 'error|fail|timeout|reset|I/O|nvme|scsi|ata|ext4|xfs'
journalctl -k --since "-2 hours"

重点关注:

  • I/O error;
  • command timeout;
  • controller reset;
  • link reset;
  • filesystem error;
  • device offline;
  • multipath path failed;
  • NVMe controller reset。

同一错误反复出现时,不应只清日志或重启。要关联设备序列号、控制器、虚拟磁盘和存储平台事件。

11.2 SMART

本地 SATA/SAS/NVMe 设备可按硬件支持使用 smartmontools:

bash
sudo smartctl -a /dev/sda
sudo smartctl -x /dev/nvme0

虚拟盘、硬件 RAID 后的逻辑盘和 SAN LUN 可能无法直接提供完整 SMART 信息,需要使用控制器、阵列或云平台工具。不要因为 smartctl 无数据就判断磁盘健康。

11.3 发现介质错误后的原则

  1. 优先保护数据和业务,不先追求“把盘修好”。
  2. 停止非必要写入,降低进一步损坏。
  3. 保存日志、SMART、阵列和平台事件。
  4. 确认冗余是否仍健康,避免第二块盘同时失败。
  5. 按存储架构执行替换、重建或迁移。
  6. 从备份验证关键数据,而不是只看 RAID 重建完成。

12. 文件系统只读、挂载失败与修复边界

文件系统检测到严重错误时,可能重新挂载为只读以保护数据。此时应用会出现写入失败、数据库停机或日志异常。

Linux 磁盘故障排查决策图

图中把设备消失、空间满、I/O 变慢和挂载失败分开。修复前先确认设备、备份和业务影响,避免对错误设备运行破坏性工具。

12.1 先确认现象

bash
findmnt -no SOURCE,FSTYPE,OPTIONS,TARGET /data/app
dmesg -T | tail -200
journalctl -k --since "-1 hour"

如果挂载选项中出现 ro,继续判断是人为只读挂载,还是文件系统错误触发。

12.2 ext4 检查

e2fsck 通常应对未挂载文件系统执行。不能对正在读写的生产文件系统直接强制检查。

bash
sudo umount /data/app
sudo e2fsck -f /dev/vg_data/lv_app

根文件系统或无法卸载的业务卷需要进入维护模式、救援环境或从其他系统启动。执行前应有备份,并保存错误信息。

12.3 XFS 检查

先使用只读检查模式:

bash
sudo umount /data/app
sudo xfs_repair -n /dev/vg_data/lv_app

确认输出和风险后,按官方文档决定是否执行实际修复。xfs_repair -L 会清除日志,可能丢失未完成的元数据更新,应视为高风险最后手段,不能作为“挂载失败就执行”的常规命令。

12.4 挂载失败常见原因

  • fstab UUID 写错或设备尚未出现;
  • LVM VG 未激活;
  • LUKS 未解锁;
  • 文件系统类型写错;
  • 挂载点不存在;
  • 文件系统需要离线修复;
  • 网络存储不可达;
  • systemd mount unit 依赖或超时错误;
  • 同一文件系统已挂载到其他位置;
  • 内核不支持对应文件系统或模块未加载。

排查:

bash
sudo findmnt --verify --verbose
sudo mount -av
systemctl --failed
journalctl -b -p warning
lsblk -f
sudo vgchange -ay

不要为了让系统启动而长期给核心数据盘加 nofail。这会把明确故障变成应用在空目录中写入数据的隐蔽事故。

13. 缩容:比扩容危险得多

扩容通常在末端增加空间;缩容要保证将要移除的区域没有有效数据,并要求文件系统、LV、分区和底层设备按严格顺序缩小。

13.1 XFS 缩容

常见生产实践不进行原地 XFS 缩容,而是:

  1. 创建新的较小 LV 和 XFS;
  2. 挂载到临时目录;
  3. 使用 xfsdump/xfsrestorersync 或应用级工具迁移;
  4. 停止写入并做增量同步;
  5. 切换挂载;
  6. 验证业务;
  7. 保留旧卷一段回滚时间。

13.2 ext4 缩容

ext4 可离线缩容,但顺序必须是先缩文件系统,再缩 LV。任何估算或命令错误都可能破坏数据。生产环境仍建议优先采用新卷迁移方案。

13.3 不要用 lvreduce 猜大小

lvreduce 缩小块设备不会理解文件系统中哪些块仍在使用。即使工具提供 --resizefs,也应先在相同发行版和文件系统版本的测试环境验证,并确保备份和停机窗口。

14. 迁移数据盘的安全流程

假设要把 /data/app 从旧 LV 迁移到新存储:

  1. 创建新设备、文件系统和临时挂载点。
  2. 验证容量、权限、挂载选项和性能。
  3. 首次在线复制大部分数据。
  4. 记录硬链接、ACL、扩展属性、稀疏文件和 SELinux 标签需求。
  5. 进入变更窗口,停止应用写入。
  6. 执行最终增量复制。
  7. 校验文件数量、容量、关键哈希和应用一致性。
  8. 更新 fstab 或挂载单元。
  9. 切换挂载并启动应用。
  10. 验证业务、日志、监控、备份和重启。
  11. 保留旧卷只读,直到回滚窗口结束。

rsync 示例需要按数据特征调整:

bash
sudo rsync -aHAXS --numeric-ids --info=progress2 \
  /data/app/ /mnt/new-app/

数据库文件不能在运行状态下简单复制并假设一致。应使用数据库备份、复制、快照一致性或厂商支持的迁移方法。

15. Swap 也是块设备管理的一部分

查看:

bash
swapon --show
free -h
cat /proc/swaps

swap 可以是分区、LV 或文件。添加 swap file:

bash
sudo fallocate -l 4G /swapfile
sudo chmod 0600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
swapon --show

持久化:

fstab
/swapfile none swap sw 0 0

某些文件系统、快照、加密或休眠场景对 swap file 有额外要求。实施前按发行版和内核文档验证。swap 不能替代内存容量规划;持续高 swap 和频繁换页通常表示内存压力或应用配置问题。

16. 自动化脚本的安全设计

磁盘自动化比人工操作更需要防误伤。脚本至少应:

  • 使用 lsblk --json 等结构化输出;
  • 根据序列号、WWN、云盘 ID 和预期容量确认设备;
  • 拒绝处理根盘、已挂载设备、已有签名设备;
  • 在破坏性操作前要求显式参数和二次确认;
  • 输出计划但默认不执行,支持 dry-run;
  • 检查命令退出码并在每层验证;
  • 记录变更前后状态;
  • 不使用模糊匹配选择 /dev/sd*
  • 对并发执行加锁;
  • 失败后停止,不自动尝试更多破坏性修复。

示例防护思路:

bash
target=/dev/disk/by-id/<expected-device-id>

test -b "$target" || exit 1
findmnt -S "$target" && exit 1
lsblk --json "$target"
sudo wipefs --no-act "$target"

这段代码仍不足以直接格式化设备,但展示了自动化应先验证事实,而不是根据“第二块盘大概是 sdb”执行。

17. 生产磁盘变更检查表

变更前

  • [ ] 已确认业务系统、数据负责人和变更窗口。
  • [ ] 已保存 lsblkfindmnt、LVM、fstab 和内核日志基线。
  • [ ] 已通过序列号、WWN 或平台磁盘 ID 确认目标。
  • [ ] 已检查设备现有签名、挂载、swap、RAID、LUKS 和 LVM 关系。
  • [ ] 已有可用备份,并明确恢复方法。
  • [ ] 已评估 I/O 影响、停机和回滚边界。

变更中

  • [ ] 每完成一层都验证容量和状态。
  • [ ] 没有使用未经确认的通配设备名。
  • [ ] 没有在挂载文件系统上运行离线修复工具。
  • [ ] 没有把 VG 容量池误认为冗余。
  • [ ] 没有消耗全部 VG 空间而忽略后续需求。
  • [ ] 日志和业务指标持续正常。

变更后

  • [ ] lsblkpvs/vgs/lvsfindmntdf 结果一致。
  • [ ] /etc/fstab 已通过 findmnt --verifymount -a
  • [ ] 应用可以读写,权限和 SELinux 上下文正确。
  • [ ] 监控容量、inode、延迟和设备健康。
  • [ ] 备份策略已覆盖新卷。
  • [ ] 已执行重启或演练验证持久挂载。
  • [ ] CMDB、容量记录和变更记录已更新。

18. 故障排查总路径

面对磁盘告警时,建议按以下顺序:

  1. 确认影响范围:单目录、单 LV、单盘、整台主机还是存储平台。
  2. 确认时间线:扩容、快照、备份、重启、补丁或硬件事件是否刚发生。
  3. 确认设备拓扑lsblkfindmnt、LVM、RAID、LUKS、多路径。
  4. 确认容量:块空间、inode、VG 空间、云盘配额。
  5. 确认 I/O:延迟、队列、吞吐、错误和超时。
  6. 确认文件系统:挂载选项、只读、内核错误、离线检查需求。
  7. 确认进程占用:删除文件、打开句柄、写入源。
  8. 确认底层健康:SMART、控制器、阵列、SAN、云平台事件。
  9. 先隔离和备份,再修复:避免故障扩大。
  10. 恢复后验证业务和数据:不能只看设备重新出现。

19. 总结

Linux 磁盘管理的核心不是掌握更多破坏性命令,而是准确识别存储栈,并按层次完成变更。应用路径下面可能是文件系统、LVM、LUKS、RAID、分区和虚拟磁盘;任何扩容、迁移或修复都必须知道自己正在操作哪一层。

日常管理应形成几个习惯:

  1. findmntlsblk 建立事实,不凭设备名猜测。
  2. 使用 UUID、LVM 路径和稳定设备标识进行持久配置。
  3. 把分区、PV、VG、LV 和文件系统视为独立层,逐层验证。
  4. 扩容通常可在线完成,缩容和修复应按高风险离线变更处理。
  5. 空间满要区分容量、inode、删除文件占用和挂载覆盖。
  6. I/O 慢要结合主机、设备、平台和应用指标。
  7. 备份、冗余和快照解决不同问题,不能互相替代。
  8. 所有破坏性操作前都应确认设备身份、业务依赖和恢复能力。

下一篇将进入《日志管理》,把 systemd journal、传统日志文件、日志轮转、集中采集、审计和容量治理串成一条完整运维链路。

参考资料



本文最后更新于 2026-06-15