Linux运维20 min read

Linux 磁盘管理实战:LVM、RAID 与数据恢复

Linux 磁盘管理实战:LVM、RAID 与数据恢复

从一次报警说起

凌晨两点,手机弹出 Zabbix 告警:/data 分区使用率 92%。SSH 上去一看,df -h` 确认只剩 80GB。但这是一台日志服务器,删旧日志只是缓兵之计——日志增长率每月 50GB,加盘才是正解。

问题来了:这台机器上线时图省事,/data 直接用了一个独立分区,不是 LVM。扩容意味着要么停机用分区工具调整大小(风险极大),要么新建分区迁移数据(需要停服)。

如果当初用了 LVM,在线加一块盘、扩容逻辑卷,整个过程不超过 5 分钟,零停机。

这篇文章不讲磁盘原理(CHS/LBA 那些已经过时了),只讲生产环境磁盘管理的实战操作:LVM 管理、RAID 配置、文件系统修复、数据恢复。

一、磁盘基础知识

1.1 磁盘识别

# 查看所有块设备
lsblk
# NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
# sda      8:0    0 500G  0 disk
# ├─sda1   8:1    0   1G  0 part /boot
# └─sda2   8:2    0 499G  0 part
#   └─vg0-root 253:0    0 499G  0 lvm  /
# sdb      8:16   0   2T  0 disk
# sdc      8:32   0   2T  0 disk
# nvme0n1 259:0    0 500G  0 disk

# 查看磁盘详细信息
fdisk -l /dev/sdb

# 查看磁盘健康状态(SMART)
smartctl -a /dev/sda
# 重点关注:
# Reallocated_Sector_Ct > 0  → 有坏道
# Current_Pending_Sector > 0 → 待处理坏扇区
# UDMA_CRC_Error_Count > 0   → 数据线问题

# 查看磁盘 IO 性能
iostat -xdm 1
# 重点关注:
# %util    → 磁盘使用率(持续 > 80% 说明瓶颈)
# await    → IO 等待时间(> 20ms 偏高,> 100ms 严重)
# r/s w/s  → 每秒读写次数
# rkB/s wkB/s → 每秒读写吞吐量

1.2 分区管理

# 新磁盘分区(推荐 parted,支持 GPT)
parted /dev/sdb mklabel gpt
parted /dev/sdb mkpart primary 0% 100%

# 或用 fdisk(传统,只支持 MBR,最大 2TB)
fdisk /dev/sdb
# n → 新建分区
# p → 主分区
# 1 → 分区号
# 回车 → 默认起始
# 回车 → 默认结束(用满)
# w → 保存

# 格式化
mkfs.xfs /dev/sdb1          # CentOS/RHEL 推荐
mkfs.ext4 /dev/sdb1         # Ubuntu/Debian 常用

# 挂载
mkdir /data
mount /dev/sdb1 /data
# 持久化挂载
echo '/dev/sdb1 /data xfs defaults 0 0' >> /etc/fstab
# 或用 UUID(更可靠)
blkid /dev/sdb1
echo 'UUID=xxx-xxx /data xfs defaults 0 0' >> /etc/fstab

为什么推荐 LVM 而不是直接分区? 因为 LVM 可以在线扩容、缩容、快照、跨磁盘。直接分区一旦空间分配完成,调整就非常麻烦。

二、LVM 逻辑卷管理

2.1 LVM 三层架构

物理磁盘 (PV)    →   卷组 (VG)    →   逻辑卷 (LV)    →   文件系统
/dev/sdb             vg_data          lv_data           /data
/dev/sdc                               lv_logs           /var/log
  • PV (Physical Volume):物理卷,一块磁盘或一个分区
  • VG (Volume Group):卷组,把多个 PV 组合成一个存储池
  • LV (Logical Volume):逻辑卷,从 VG 中分配空间,相当于"虚拟分区"

2.2 创建 LVM

# 1. 创建 PV
pvcreate /dev/sdb /dev/sdc
# Physical volume "/dev/sdb" successfully created.
# Physical volume "/dev/sdc" successfully created.

# 查看
pvdisplay
# PV Name       /dev/sdb
# VG Name       vg_data
# PV Size       2.00 TiB
# Allocatable   yes

pvs  # 简洁版
# PV         VG     Fmt  Attr PSize   PFree
# /dev/sdb   vg_data lvm2 a--   2.00t  1.00t
# /dev/sdc   vg_data lvm2 a--   2.00t  2.00t

# 2. 创建 VG
vgcreate vg_data /dev/sdb /dev/sdc
# Volume group "vg_data" successfully created

# 查看
vgs
# VG      #PV #LV #SN Attr   VSize VFree
# vg_data   2   0   0 wz--n- 4.00t 4.00t

# 3. 创建 LV
# 方式一:指定大小
lvcreate -L 500G -n lv_data vg_data

# 方式二:使用全部剩余空间
lvcreate -l 100%FREE -n lv_logs vg_data

# 方式三:指定百分比
lvcreate -l 50%VG -n lv_data vg_data

# 查看
lvs
# LV      VG     Attr       LSize
# lv_data vg_data -wi-ao---- 500.00g
# lv_logs vg_data -wi-ao---- 3.50t

# 4. 格式化并挂载
mkfs.xfs /dev/vg_data/lv_data
mkdir /data
mount /dev/vg_data/lv_data /data

# 持久化
echo '/dev/vg_data/lv_data /data xfs defaults 0 0' >> /etc/fstab

2.3 在线扩容(重点!)

这是 LVM 最大的价值——不停机扩容。

# 场景:/data 空间不足,加了一块新磁盘 /dev/sdd

# 1. 将新磁盘加入 VG
pvcreate /dev/sdd
vgextend vg_data /dev/sdd

# 2. 扩展 LV(使用 VG 中全部剩余空间)
lvextend -l 100%FREE /dev/vg_data/lv_data
# 或指定大小
lvextend -L +500G /dev/vg_data/lv_data
# 或指定最终大小
lvextend -L 2T /dev/vg_data/lv_data

# 3. 扩展文件系统(关键!很多人忘这步)
# XFS:
xfs_growfs /data
# EXT4:
resize2fs /dev/vg_data/lv_data

# 4. 验证
df -h /data
# /dev/mapper/vg_data-lv_data  4.0T  1.2T  2.8T  30% /data

整个过程不需要卸载文件系统,不需要停服务。 这就是 LVM 的魅力。

2.4 在线缩容

# 注意:XFS 不支持缩容!只有 EXT4 可以缩容。

# EXT4 缩容:
# 1. 先卸载(必须!)
umount /data

# 2. 检查文件系统
e2fsck -f /dev/vg_data/lv_data

# 3. 缩小文件系统
resize2fs /dev/vg_data/lv_data 300G

# 4. 缩小 LV
lvreduce -L 300G /dev/vg_data/lv_data
# 警告: shrinking a logical volume with data on it may cause data loss!
# 输入 y 确认

# 5. 重新挂载
mount /dev/vg_data/lv_data /data

安全缩容建议:先缩小文件系统到比目标大一点(如目标 300G,先缩到 310G),再缩小 LV 到 300G,最后再 resize2fs 到 300G。多一步但更安全。

2.5 LVM 快照

快照是 LVM 的另一个杀手级功能——瞬间创建一个逻辑卷的时间点副本。

# 创建快照(大小为源 LV 的 10-20%,存储变化的数据)
lvcreate -L 50G -s -n lv_data_snapshot /dev/vg_data/lv_data

# 挂载快照
mkdir /mnt/snapshot
mount /dev/vg_data/lv_data_snapshot /mnt/snapshot

# 现在可以在快照上做备份,不影响源卷的正常读写

# 备份完成后删除快照
umount /mnt/snapshot
lvremove /dev/vg_data/lv_data_snapshot

快照的实际用途

  • 数据库热备份:先做 LVM 快照,再从快照中备份数据文件,保证一致性
  • 变更前回滚点:升级前做快照,出问题可以从快照恢复
  • 测试环境:从生产快照创建测试卷

快照恢复

# 将源卷回滚到快照时间点(源卷数据丢失!)
lvconvert --merge /dev/vg_data/lv_data_snapshot
# 需要重新激活 LV 才生效
lvchange -an /dev/vg_data/lv_data
lvchange -ay /dev/vg_data/lv_data

2.6 LVM 常用诊断

# 查看所有 PV/VG/LV
pvs && vgs && lvs

# 详细信息
pvdisplay
vgdisplay
lvdisplay

# 查看 LV 的映射关系
lsblk

# 查看 VG 的物理分布
pvdisplay -m

# 查看哪些 PV 在哪些 VG
pvdisplay -C

# LVM 日志
journalctl -u lvm2-monitor

三、RAID 阵列配置

3.1 RAID 级别选择

级别 最少磁盘 冗余 可用容量 适用场景
RAID 0 2 100% 临时数据、性能优先
RAID 1 2 1块 50% 系统盘、小容量高可靠
RAID 5 3 1块 (n-1)/n 通用、读多写少
RAID 6 4 2块 (n-2)/n 大容量、高可靠
RAID 10 4 每对1块 50% 高性能+高可靠

生产建议

  • 系统盘:RAID 1(两块 SSD)
  • 数据盘:RAID 10(性能要求高)或 RAID 6(容量要求高)
  • 备份盘:RAID 6(大容量 + 双盘容错)

3.2 软件 RAID 配置(mdadm)

# 安装
apt install mdadm   # Ubuntu
yum install mdadm   # CentOS

# 创建 RAID 10(4块磁盘)
mdadm --create /dev/md0 --level=10 --raid-devices=4 /dev/sd{b,c,d,e}
# mdadm: Defaulting to version 1.2 metadata
# mdadm: array /dev/md0 started.

# 查看状态
mdadm --detail /dev/md0
# State : clean
# Active Devices : 4
# Working Devices : 4
# Layout : near=2

cat /proc/mdstat
# md0 : active raid10 sde[3] sdd[2] sdc[1] sdb[0]
#       4194304 blocks super 1.2 512K chunks 2 nearcopies [4/4] [UUUU]

# 格式化并使用
mkfs.xfs /dev/md0
mount /dev/md0 /data

# 保存配置(重启后自动组装)
mdadm --detail --scan >> /etc/mdadm.conf
# Ubuntu 还需要更新 initramfs
update-initramfs -u

3.3 RAID 维护

# 查看健康状态
mdadm --detail /dev/md0 | grep -E "State|Active|Working|Failed|Spare"

# 监控重建进度
watch -n 5 'cat /proc/mdstat'

# 替换故障磁盘
# 1. 标记故障
mdadm /dev/md0 --fail /dev/sdb
# 2. 移除
mdadm /dev/md0 --remove /dev/sdb
# 3. 插入新磁盘后添加
mdadm /dev/md0 --add /dev/sdb
# 4. 观察重建
cat /proc/mdstat
# [UU_U] → [UUUU] 重建中

# 添加热备盘
mdadm /dev/md0 --add-spare /dev/sdf

# 停止并删除 RAID(谨慎!)
umount /dev/md0
mdadm --stop /dev/md0
mdadm --zero-superblock /dev/sd{b,c,d,e}

3.4 RAID + LVM 组合

生产环境推荐 RAID 做底层冗余,LVM 做上层管理:

# 1. 先建 RAID
mdadm --create /dev/md0 --level=10 --raid-devices=4 /dev/sd{b,c,d,e}

# 2. 在 RAID 设备上建 LVM
pvcreate /dev/md0
vgcreate vg_data /dev/md0
lvcreate -L 1T -n lv_data vg_data

# 3. 格式化使用
mkfs.xfs /dev/vg_data/lv_data
mount /dev/vg_data/lv_data /data

四、文件系统管理

4.1 XFS vs EXT4

特性 XFS EXT4
最大文件 8EB 16TB
在线扩容 支持 支持
在线缩容 不支持 支持
元数据日志
快照支持 LVM快照 LVM快照
默认 RHEL/CentOS Ubuntu/Debian
大文件性能 优秀 良好
小文件性能 良好 优秀

选择建议:CentOS/RHEL 用 XFS,Ubuntu 用 EXT4,不确定就选 XFS(扩容方便)。

4.2 文件系统检查与修复

# XFS 检查(只读,不修复)
xfs_db -c frag /dev/vg_data/lv_data
# 查看碎片率

# XFS 修复(必须卸载!)
umount /data
xfs_repair /dev/vg_data/lv_data
# 如果修复失败,加 -L 强制日志清零(可能丢数据)
xfs_repair -L /dev/vg_data/lv_data

# EXT4 检查
e2fsck -f /dev/vg_data/lv_data

# EXT4 修复
e2fsck -p /dev/vg_data/lv_data    # 自动修复
e2fsck -y /dev/vg_data/lv_data    # 全部回答 yes

# 开机自动检查
tune2fs -c 30 /dev/sda1   # 每30次挂载检查一次
tune2fs -i 30d /dev/sda1  # 每30天检查一次

4.3 磁盘碎片整理

# XFS 查看碎片
xfs_db -c frag /dev/vg_data/lv_data
# 实际块数 / 理想块数 = 碎片率
# 碎片率 > 30% 才需要整理

# XFS 整理(需要挂载状态)
xfs_fsr /dev/vg_data/lv_data

# EXT4 查看碎片
e4defrag -c /data
# Fragmentation score: 5
# 0-30 不需要整理

# EXT4 整理
e4defrag /data

注意:现代文件系统碎片化问题不严重,XFS 和 EXT4 都有预分配机制。SSD 更不需要整理碎片。

4.4 磁盘配额

# 启用配额(XFS)
# /etc/fstab 中添加 prjquota 或 usrquota
echo '/dev/vg_data/lv_data /data xfs defaults,prjquota 0 0' >> /etc/fstab
mount -o remount /data

# 设置目录配额
xfs_quota -x -c 'limit bhard=50g bsoft=40g -d /data/logs'

# 查看配额
xfs_quota -x -c 'report -h'

五、数据恢复实战

5.1 误删文件恢复(extundelete)

# 场景:rm -rf 误删了 /data/important/

# 第一步:立即将分区挂载为只读,防止数据被覆盖!
mount -o remount,ro /data

# 安装工具
apt install extundelete   # Ubuntu

# 恢复指定目录
extundelete /dev/vg_data/lv_data --restore-directory important

# 恢复指定文件
extundelete /dev/vg_data/lv_data --restore-file important/config.yaml

# 恢复全部
extundelete /dev/vg_data/lv_data --restore-all

# 恢复的文件在当前目录的 RECOVERED_FILES/ 下

注意:extundelete 只支持 EXT3/EXT4。XFS 没有好的文件级恢复工具。一旦误删,恢复概率取决于数据块是否被覆盖。

5.2 误删分区恢复(testdisk)

# 场景:误删了分区表
apt install testdisk

# 运行
testdisk
# 1. 选择磁盘
# 2. 选择 Intel (MBR) 或 GPT
# 3. 选择 Analyse → Quick Search
# 4. testdisk 会扫描并显示找到的分区
# 5. 确认后选择 Write 恢复分区表

5.3 LVM PV 丢失恢复

# 场景:重装系统后 VG 找不到了,但 PV 数据还在

# 扫描 PV
pvscan
# PV /dev/sdb VG vg_data lvm2 [2.00 TiB / 0 free]

# 如果 pvscan 没找到,手动扫描
pvcreate --restorefile /etc/lvm/archive/vg_data_*.vg /dev/sdb

# 恢复 VG
vgcfgrestore vg_data

# 激活 VG
vgchange -ay vg_data

# 检查 LV
lvs
mount /dev/vg_data/lv_data /data

5.4 RAID 超级块损坏恢复

# 场景:md0 突然消失,mdadm --assemble 失败

# 查看磁盘上的 RAID 超级块
mdadm --examine /dev/sdb

# 如果超级块还在,重新组装
mdadm --assemble /dev/md0 /dev/sd{b,c,d,e}

# 如果超级块损坏,强制组装
mdadm --assemble --force /dev/md0 /dev/sd{b,c,d,e}

# 如果某块盘的超级块损坏,用其他盘恢复
mdadm --create /dev/md0 --level=10 --raid-devices=4 /dev/sdb /dev/sdc /dev/sdd missing
# 注意:用 missing 替代坏盘,然后正常 add 新盘

5.5 数据恢复的黄金法则

1. 发现数据丢失 → 立即停止写入!挂载只读!
2. 不要在原磁盘上操作 → 先 dd 整盘镜像到另一块盘
3. 在镜像上做恢复操作
4. 恢复是概率事件,不保证100%成功
5. 最佳恢复方案 = 定期备份(lsnapshot/rsync/bareos)
# 创建磁盘镜像(在恢复前先做镜像)
dd if=/dev/sdb of=/dev/sdc bs=4M status=progress

# 或创建到文件
dd if=/dev/sdb of=/backup/sdb.img bs=4M status=progress

# 在镜像上操作
losetup /dev/loop0 /backup/sdb.img
# 然后对 /dev/loop0 做恢复操作

六、磁盘性能测试

6.1 基准测试(fio)

# 安装
apt install fio

# 顺序读写测试(适合评估大文件性能)
fio --name=seqwrite --ioengine=libaio --iodepth=1 \
    --rw=write --bs=1M --size=1G --numjobs=1 \
    --runtime=60 --time_based --directory=/data

fio --name=seqread --ioengine=libaio --iodepth=1 \
    --rw=read --bs=1M --size=1G --numjobs=1 \
    --runtime=60 --time_based --directory=/data

# 随机读写测试(适合评估数据库性能)
fio --name=randwrite --ioengine=libaio --iodepth=32 \
    --rw=randwrite --bs=4k --size=1G --numjobs=4 \
    --runtime=60 --time_based --directory=/data

fio --name=randread --ioengine=libaio --iodepth=32 \
    --rw=randread --bs=4k --size=1G --numjobs=4 \
    --runtime=60 --time_based --directory=/data

# 混合读写测试(模拟生产负载)
fio --name=mixed --ioengine=libaio --iodepth=32 \
    --rw=randrw --rwmixread=70 --bs=4k --size=1G --numjobs=4 \
    --runtime=60 --time_based --directory=/data

性能参考值

磁盘类型 顺序写 顺序读 随机写(IOPS) 随机读(IOPS)
HDD 7200rpm 150 MB/s 180 MB/s 100 150
SATA SSD 500 MB/s 550 MB/s 80K 90K
NVMe SSD 2000 MB/s 3000 MB/s 300K 500K
RAID 10 (HDD×4) 400 MB/s 500 MB/s 350 500

6.2 简单测试(dd)

# 写测试(注意:不准确的基准,但快速粗略)
dd if=/dev/zero of=/data/testfile bs=1M count=1024 oflag=direct
# 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 2.1 s, 500 MB/s

# 读测试
dd if=/data/testfile of=/dev/null bs=1M iflag=direct
rm /data/testfile

6.3 IO 监控

# 实时 IO 监控
iostat -xdm 1

# 进程级 IO 监控
iotop -oP
# 只显示有 IO 活动的进程

# 查看哪个进程在读写磁盘
lsof /data

七、生产环境最佳实践

7.1 磁盘分区规划

挂载点 大小 类型 说明
/boot 1GB 独立分区 存放内核,避免 LVM
/ 50-100GB LVM 系统根分区
/data 按需 LVM on RAID 数据分区
swap 内存×1~2 独立分区或文件 物理内存的1-2倍
/var/log 20-50GB LVM 日志分区,防止日志撑爆根分区
# /etc/fstab 生产配置示例
/dev/vg0/root    /         xfs    defaults                       0 0
UUID=xxx         /boot     xfs    defaults                       0 0
/dev/vg0/swap    swap      swap   defaults                       0 0
/dev/vg_data/lv_data  /data  xfs  defaults,noatime,nodiratime    0 0
/dev/vg0/logs    /var/log  xfs    defaults                       0 0

noatime:不更新文件访问时间,减少 IO。对数据盘和日志盘推荐。

7.2 定期检查清单

#!/bin/bash
# disk-health-check.sh

echo "=== 磁盘使用率 ==="
df -h | grep -vE 'tmpfs|loop'

echo -e "\n=== LVM 状态 ==="
lvs 2>/dev/null || echo "LVM not configured"
vgs 2>/dev/null

echo -e "\n=== RAID 状态 ==="
for md in /dev/md*; do
    [ -b "$md" ] && echo "$md:" && mdadm --detail "$md" | grep -E "State|Active|Failed"
done

echo -e "\n=== SMART 健康 ==="
for disk in $(lsblk -d -n -o NAME | grep -E 'sd|nvme'); do
    echo "/dev/$disk:"
    smartctl -H /dev/$disk 2>/dev/null | grep -E "result|PASSED|FAILED"
done

echo -e "\n=== IO 等待 ==="
iostat -x 1 3 | tail -20

echo -e "\n=== 大文件 TOP10 ==="
find /data -type f -size +1G -exec ls -lh {} \; 2>/dev/null | sort -k5 -rh | head -10

加入 cron:

# 每天早上8点检查
echo '0 8 * * * /opt/scripts/disk-health-check.sh | mail -s "Disk Health Report" ops@example.com' | crontab -

7.3 自动告警

# 磁盘使用率告警(配合 Zabbix/Prometheus)
# 或简单脚本:
#!/bin/bash
THRESHOLD=85
ALERT_EMAIL="ops@example.com"

df -h | awk 'NR>1 && $5+0 > '$THRESHOLD' {print $5, $6}' | while read usage mountpoint; do
    echo "警告:$mountpoint 使用率 $usage(超过 ${THRESHOLD}%)" | \
    mail -s "磁盘空间告警" "$ALERT_EMAIL"
done

总结

磁盘管理是运维的基本功。记住几个核心原则:

  1. 永远用 LVM:不管是数据盘还是系统盘,LVM 的在线扩容和快照功能在关键时刻能救命
  2. 重要数据用 RAID:单盘故障不丢数据是底线,RAID 10 或 RAID 6
  3. 定期检查 SMART:坏道是渐进的,不要等到磁盘完全失效才发现
  4. 备份比恢复靠谱:数据恢复是概率事件,定期备份是确定性保障
  5. 误删后立即停止写入:越早停止写入,恢复概率越高

最后回到开头那个故事。后来那台日志服务器花了一个周末迁移到 LVM,从此扩容就是 pvcreate → vgextend → lvextend → xfs_growfs 四条命令的事。运维的价值不在于处理了多少故障,而在于让多少故障不再发生。

分享:

相关文章

评论区