本页内容
Linux 软 RAID(即由 mdadm 管理的内核 md 驱动)是在独立服务器上为 NVMe 硬盘做镜像的标准方式。它是主线内核的一部分,无需特殊驱动即可引导,只需消耗少量 CPU 时间,省去了 RAID 控制卡。本指南介绍何时选用 RAID 1 或 RAID 10、如何检查和创建阵列、如何监控阵列,以及如何在不影响引导的前提下更换故障的 NVMe 硬盘。
文中命令适用于 Ubuntu 24.04 和 Debian 12/13,均以 root 身份运行。在 AlmaLinux 和 Rocky Linux 上,配置文件为 /etc/mdadm.conf,并使用 dracut -f 重建 initramfs。
RAID 1 还是 RAID 10
| 硬盘数 | 级别 | 可用容量 | 可容忍的故障 | FlexDedi 示例 |
|---|---|---|---|---|
| 2 | RAID 1 | 一块硬盘 | 一块硬盘故障 | Core 16、Core 16X、Pro 32、Pro 48、GPU 服务器 |
| 4 | RAID 10 | 两块硬盘 | 每个镜像对一块硬盘故障 | Pro 64、Max 96、Max 192 |
RAID 1 会把每个数据块同时写入两块硬盘,读取时可以从任意一块读取,有利于并行读;写入速度与单块硬盘相当。RAID 10 在两个镜像之间做条带化,因此四块硬盘的可用容量是双盘镜像的两倍,写入吞吐量也更高。校验型 RAID(5 或 6)能提供更多容量,但会增加写入开销,重建时间也很长,所以对于运行在四块 NVMe 硬盘上的数据库和虚拟机,通常选择 RAID 10。
RAID 0 没有冗余,只适合存放临时数据。任何 RAID 级别都不能替代备份:RAID 只能防范硬盘损坏,防不了 rm -rf、软件写入的数据损坏或主机被入侵。
如果你运行的是 Proxmox VE,请改用它自带的 ZFS 镜像,因为 Proxmox 不支持 mdadm;参见在独立服务器上安装 Proxmox VE。
检查安装程序创建的阵列
包括 Debian 和 Ubuntu 在内的安装程序,都可以在安装过程中创建 md 阵列。在做任何更改之前,先弄清楚系统中已有哪些阵列:
cat /proc/mdstat
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS
mdadm --detail /dev/md0健康的镜像阵列看起来是这样的:
Personalities : [raid1]
md0 : active raid1 nvme1n1p2[1] nvme0n1p2[0]
3749557248 blocks super 1.2 [2/2] [UU]
bitmap: 1/28 pages [4KB], 65536KB chunk[2/2] [UU] 表示有两个成员,且都在正常运行。[2/1] 加上 [U_] 或 [_U] 表示阵列已降级,标记为 (F) 的成员已经故障。重建期间,recovery = 这一行会显示进度和预计完成时间。
接着检查服务器的引导方式。UEFI 固件无法读取默认元数据格式的 md 阵列,因此 EFI 系统分区(ESP)位于 RAID 之外。安装程序通常会在每块硬盘上都创建一个 ESP,但只挂载并写入其中一个,挂载点为 /boot/efi:
lsblk -o NAME,SIZE,PARTTYPENAME,MOUNTPOINTS
efibootmgr -v如果只有一块硬盘上有写入了内容的 ESP 和引导项,那么这块硬盘一旦损坏,服务器就无法启动。下文「让两块硬盘都能引导」一节会解决这个问题。
创建阵列
在新服务器上,最省事的做法是让安装程序创建 RAID 1。如果要自己创建阵列,例如在四盘服务器的两块空闲硬盘上创建数据阵列,请使用 Linux RAID 类型的分区而不是整块磁盘,并在磁盘末尾留出一点空间,这样即使替换硬盘的扇区数略少,也依然放得下:
sgdisk --zap-all /dev/nvme2n1
sgdisk -n 1:0:-100M -t 1:FD00 /dev/nvme2n1
sgdisk --replicate=/dev/nvme3n1 /dev/nvme2n1
sgdisk --randomize-guids /dev/nvme3n1
mdadm --create /dev/md1 --level=1 --raid-devices=2 --bitmap=internal \
/dev/nvme2n1p1 /dev/nvme3n1p1对于 RAID 10,用同样的方法为四块硬盘分区,并以四个分区配合 --level=10 --raid-devices=4 创建阵列。写意图位图(write-intent bitmap)让阵列在崩溃或某个成员短暂缺失之后,只需重新同步发生了变化的区域。
创建文件系统,按 UUID 挂载,并记录阵列信息,使其在启动时以相同的名称组装:
mkfs.ext4 /dev/md1
mkdir -p /srv/data
echo "UUID=$(blkid -s UUID -o value /dev/md1) /srv/data ext4 defaults,nofail 0 2" >> /etc/fstab
systemctl daemon-reload && mount /srv/data
mdadm --detail --scan | grep /dev/md1 >> /etc/mdadm/mdadm.conf
update-initramfs -u阵列创建后即可使用,初始同步会在后台进行;可以用 watch -n 5 cat /proc/mdstat 跟踪进度。
监控阵列
悄无声息降级的镜像,其实就是一块随时可能坏掉的单盘,所以一定要确保有告警能通知到你。
mdadm --monitor
Debian 和 Ubuntu 以 mdmonitor 服务的形式运行 mdadm --monitor。它会把 Fail、DegradedArray 等事件报告给 /etc/mdadm/mdadm.conf 中 MAILADDR 设置的地址,这需要服务器上有可用的邮件传输代理(MTA)。如果服务器无法发送邮件,可以添加一行 PROGRAM,改为运行你指定的可执行程序。mdadm 会把事件名称、阵列以及相关的成员设备(如有)传给它,足以推送到聊天工具或告警呼叫的 Webhook。
MAILADDR root
PROGRAM /usr/local/sbin/md-alert编辑文件后重启服务,然后确认告警确实能够送达。第二条命令会为每个阵列发送一个 TestMessage 事件:
systemctl restart mdmonitor && systemctl status mdmonitor
mdadm --monitor --scan --test --oneshot定期检查与指标
Debian 和 Ubuntu 还会定期对 md 阵列执行一致性检查。你也可以手动启动一次检查,并在完成后查看结果:
echo check > /sys/block/md0/md/sync_action
cat /sys/block/md0/md/mismatch_cnt如果你使用 Prometheus,node exporter 的 mdadm 采集器会暴露 node_md_disks{state="failed"} 指标;只要该值大于零就应告警。同时也要监控硬盘本身,因为 smartd 和 nvme smart-log 往往能在硬盘故障之前发出预警。两者在 Linux 安全基线中都有介绍。
更换故障的 NVMe 硬盘
一块硬盘故障后,阵列会依靠剩下的那块继续运行。请尽快更换:在重建完成之前,再坏一块硬盘,数据就会丢失。
1. 通过序列号识别硬盘
nvme0、nvme1 这类 NVMe 设备名是在启动时分配的,可能发生变化,因此要通过序列号识别故障硬盘,绝不能只看设备名:
mdadm --detail /dev/md0 # which member is faulty or removed
nvme list # device, model and serial number
ls -l /dev/disk/by-id/ | grep nvme # serial-based names for each device2. 将其从所有阵列中移除
如果这块硬盘的分区分属多个阵列(例如根分区和交换分区),要逐一将其标记为故障并移除:
mdadm --manage /dev/md0 --fail /dev/nvme1n1p2 --remove /dev/nvme1n1p2如果该设备已经消失,用 mdadm /dev/md0 --remove detached 清除失效的条目。
3. 申请更换硬盘
向技术支持提交工单,并注明故障硬盘和健康硬盘的序列号,以免换错硬盘。FlexDedi 在每个机房都备有现场备件。请预留一个维护窗口,以防更换过程中需要断电重启。
4. 将分区表复制到新硬盘
更换完成后,用 lsblk 和 nvme list 确认哪个设备是新的空白硬盘。然后从健康硬盘复制分区布局:
sgdisk --replicate=/dev/nvme1n1 /dev/nvme0n1 # new drive first, healthy drive last
sgdisk --randomize-guids /dev/nvme1n15. 重新加入阵列并重建
mdadm --manage /dev/md0 --add /dev/nvme1n1p2
watch -n 5 cat /proc/mdstat重建速度受 dev.raid.speed_limit_min 和 dev.raid.speed_limit_max 限制,通常分别为 1,000 和 200,000 KB/s;可以用 sysctl dev.raid 查看你的设置。以约 200 MB/s 的速度重建一个 3.84 TB 的镜像,大约需要五个小时(估算:3,840,000 MB ÷ 200 MB/s ≈ 5.3 小时)。NVMe 硬盘的速度可以快得多,因此提高上限能缩短阵列暴露在风险中的时间,代价是会占用运行中业务的一部分 I/O:
sysctl -w dev.raid.speed_limit_max=20000006. 让新硬盘可以引导
新硬盘上的 ESP 是空的。请先删除 /etc/fstab 中引用旧 ESP UUID 的条目,再按照下一节的说明重新创建 ESP。
让两块硬盘都能引导
仅仅镜像根文件系统还不够:如果存放活动 ESP 的硬盘损坏,固件必须能在另一块硬盘上找到引导加载程序。在 UEFI 系统上,需要格式化第二个 ESP、复制文件并注册一个引导项。请先查看 /boot/efi/EFI/ 下的目录名,例如 debian 或 ubuntu:
mkfs.vfat -F 32 /dev/nvme1n1p1
mkdir -p /boot/efi2
echo "UUID=$(blkid -s UUID -o value /dev/nvme1n1p1) /boot/efi2 vfat umask=0077,nofail 0 1" >> /etc/fstab
systemctl daemon-reload && mount /boot/efi2
cp -r /boot/efi/. /boot/efi2/
efibootmgr --create --disk /dev/nvme1n1 --part 1 --label "debian disk 2" --loader '\EFI\debian\shimx64.efi'GRUB 和 shim 更新只会写入第一个 ESP,因此每次更新后都要重新复制。用一个 APT 钩子即可自动完成:
cat > /etc/apt/apt.conf.d/99-sync-esp <<'EOF'
DPkg::Post-Invoke { "if mountpoint -q /boot/efi2; then cp -r /boot/efi/. /boot/efi2/; fi"; };
EOF在 Ubuntu 上,也可以改用 dpkg-reconfigure grub-efi-amd64 注册多个 ESP,让 GRUB 安装到所有 ESP 上。在传统 BIOS 系统上,dpkg-reconfigure grub-pc 可以让你同时选择两块硬盘。请在维护窗口内通过 KVM 控制台,在固件启动菜单中选择第二块硬盘,测试配置是否生效。
md RAID 上的 TRIM
RAID 1 和 RAID 10 会把 discard(TRIM)请求透传给成员硬盘,有助于 NVMe 保持写入性能并控制磨损。先确认 discard 请求能够到达阵列,然后使用定期运行的 fstrim 定时器,而不要使用 discard 挂载选项,因为后者会在每次删除时都发出 TRIM:
lsblk --discard /dev/md0 # non-zero DISC-GRAN and DISC-MAX mean TRIM works
systemctl enable --now fstrim.timer
fstrim -av这样做有一个副作用:如果硬盘对已 TRIM 的块不返回全零,之后的一致性检查可能会针对没有任何文件系统使用的空间,报告非零的 mismatch_cnt。nvme id-ns -H /dev/nvme0n1 可以显示硬盘读取已释放块时的行为。TRIM 之后出现少量且稳定的不一致计数,本身并不意味着数据损坏;但如果在繁忙的阵列上该计数持续增长,就值得深入调查。
在 FlexDedi 上运行
FlexDedi 的每台服务器都至少配备两块 NVMe 硬盘,可组建 RAID 1,例如 Core 16($299/月)配备 2 × 1.92 TB Gen4,Pro 32($749/月)配备 2 × 3.84 TB Gen5。如需 RAID 10,Pro 64($1,349/月)配备 4 × 3.84 TB Gen5,可用容量 7.68 TB;Max 96($1,899/月)配备 4 × 7.68 TB,可用容量 15.36 TB。如果更换硬盘后服务器无法启动,可以通过 KVM 控制台和救援模式进行修复,替换硬盘则直接取自现场备件。