RAID 10 是什么?VPS 为何选它存储 NVMe
了解 RAID 1、5、6 和 10 可承受的硬盘故障、容量与写入代价,掌握如何读取 /proc/mdstat,以及 RAID 10 在 NVMe VPS 上更易重建的原因。
RAID 10 的工作原理,以及 VPS 主机为何使用它
RAID 10 是大多数 VPS 主机在虚拟化 NVMe(非易失性内存快速)硬盘上采用的存储布局。它先将每块硬盘镜像到一个配对硬盘,再将数据条带化写入这些镜像对。单块硬盘故障时,阵列仍可继续运行;修复时只需从正常的配对硬盘复制数据,而不必重新计算并读取阵列中的其他所有硬盘。
RAID 是独立磁盘冗余阵列的缩写。它只有一个作用:在硬盘故障或更换期间,保持机器继续提供服务。这个作用是可用性,而不是安全性。
RAID 会复制您的写入操作。rm -rf /srv 也是一次写入。镜像的两端会在同一毫秒内删除该目录,但阵列之后仍会报告自身状态正常。
请记住这句话。本页其余内容将介绍每个级别可以承受哪些故障,以及每次写入会产生什么代价。最后几节介绍如何在您拥有的机器上使用命令查看阵列状态,以及 RAID 从未覆盖的故障类型。
托管服务购买者实际会遇到的级别:1、5、6 和 10
套餐页面通常只列出一个数字。这个数字回答两个问题:最多可以损坏多少块硬盘,以及每次写入需要付出什么代价。
RAID 1 是镜像。 两块硬盘保存相同的数据块。每次写入都会发送到两块硬盘。任意一块硬盘都可以处理读取请求。一块硬盘发生故障时不会丢失数据,但原始容量只有一半可用。由于不需要计算校验信息,写入路径较短。
RAID 5 是带有每条条带一个校验块的条带化。 使用 n 块硬盘时,可获得其中 n-1 块硬盘的容量,并且阵列恰好可以承受一块硬盘故障。校验信息不会固定存放在某一块硬盘上,而是轮流分布在所有硬盘中。因此,每块硬盘都同时承载数据和校验信息。
RAID 6 为每条条带增加第二个独立的校验块,通常记为 P 和 Q。它可以承受任意两块硬盘同时发生故障。这一点比看起来更重要,因为第二次故障最常发生在第一次故障的修复期间。
RAID 10 是镜像组组成的条带。 硬盘两两组成镜像,数据再分布到各个镜像组中。可用容量是原始总容量的一半,与 RAID 1 相同,同时具备条带化带来的并行能力。
您还会看到 RAID 1+0 这种写法,这才是准确的描述:先做镜像,再跨镜像组进行条带化。RAID 0+1 的顺序相反:先做条带化,再镜像两个条带。它更差,因为一块硬盘故障就会使整个条带停止服务,修复时必须复制另一侧的全部数据。
Linux 是一个值得了解的特殊情况。内核的 raid10 是单一实现,而不是两个叠加的层,因此可以使用奇数块硬盘运行,并提供嵌套配置无法表示的布局(near、far、offset)。因此,Linux 主机上的状态行会显示 2 near-copies,而不是列出两个阵列。
The data behind this chart
[
{
"label": "RAID 1 (four mirrored pairs)",
"usable_tb": 4,
"worst_case_drives_lost": 1,
"best_case_drives_lost": 4
},
{
"label": "RAID 5",
"usable_tb": 7,
"worst_case_drives_lost": 1,
"best_case_drives_lost": 1
},
{
"label": "RAID 6",
"usable_tb": 6,
"worst_case_drives_lost": 2,
"best_case_drives_lost": 2
},
{
"label": "RAID 10",
"usable_tb": 4,
"worst_case_drives_lost": 1,
"best_case_drives_lost": 4
}
]8 块 1 TB 硬盘在 RAID 5 下可提供 7 TB 的可用空间,在 RAID 10 下可提供 4 TB。这个差距会直接影响成本,也是校验方案不断被提出的原因。RAID 6 在任意故障模式下都可以承受 2 次故障。RAID 10 只能保证 1,因为最危险的第二次故障,是发生在第一块故障硬盘的镜像伙伴上。只要没有两次故障发生在同一对镜像硬盘上,它最多可以承受 4 次故障;但这取决于运气,并不是设计特性。
每次写入各级别的成本
写入镜像相当于执行两次写入,同时发送到两个成员。写入校验条带的工作量更大,因为该条带的校验块已经失效,必须重新计算。
控制器无法仅根据新数据块重新计算校验值。它必须先读取旧数据块和旧校验块。因此,RAID 5 上的一次小型随机写入会变成读取、读取、写入、写入。RAID 6 还需要维护第二个校验值,因此同一次写入会变成读取、读取、读取、写入、写入、写入。
The data behind this chart
[
{
"label": "RAID 1 (2 drives)",
"write_ops_per_host_write": 2,
"drives_read_to_rebuild": 1
},
{
"label": "RAID 5 (8 drives)",
"write_ops_per_host_write": 4,
"drives_read_to_rebuild": 7
},
{
"label": "RAID 6 (8 drives)",
"write_ops_per_host_write": 6,
"drives_read_to_rebuild": 7
},
{
"label": "RAID 10 (8 drives)",
"write_ops_per_host_write": 2,
"drives_read_to_rebuild": 1
}
]一次小型随机写入在 RAID 6 上需要 6 次设备操作,在 RAID 10 上需要 2 次。仅看次数会低估延迟差异。两次镜像写入会并行发出,因此客户机需要等待其中较慢的一次。校验路径中包含一次读取,必须完成后才能计算新的校验值,因此客户机需要先等待读取,再等待写入,两个操作依次进行。在繁忙的主机上,这次读取还会排在其他人的 I/O 后面。
但有一个重要例外。一次足以填满整个条带的写入不需要读取旧数据,因为条带中的每个块都会被替换。校验值可根据内存中已有的数据计算,额外成本降为一次写入。这就是 RAID 5 在顺序基准测试中表现良好,却在多个租户产生小型写入的混合负载下表现糟糕的原因。应测试实际运行的负载模式:正确测试 VPS 磁盘性能意味着在合理的队列深度下执行随机 I/O,而不是执行一次大型 dd。
重建为何是危险环节
奇偶校验重建必须根据其余所有内容重建缺失的磁盘,因此会从第一个块读取到最后一个块,共读取 7 个正常磁盘。RAID 10 重建只读取 1 个:故障磁盘的镜像伙伴磁盘,不读取其他磁盘。
这会带来两项成本。第一项是时间成本,因为重建速度受最慢的正常磁盘以及额外的奇偶校验计算限制。第二项是负载。奇偶校验组中的每个磁盘在整个重建期间都处于繁忙状态,因此该节点上的每个虚拟机都会遇到更高的延迟,直到重建结束。RAID 10 只有其中一对磁盘繁忙,其他磁盘对仍按正常速度提供服务。
同一期间还存在数据正确性风险。RAID 5 阵列在一块磁盘故障后已没有冗余,因此只要任一正常磁盘上存在无法读取的扇区,该扇区就无法恢复。重建是唯一会读取每个扇区的操作,也包括过去一年中从未被访问过的扇区。公开的数据表规格显示,消费级硬盘读取 10^14 个比特时可能出现约 1 个不可恢复读取错误;企业级 NVMe 磁盘的指标则为每读取 10^17 个比特出现 1 个错误,或更好。这些是厂商规格而非实际测量值,但这个比例说明了为什么“RAID 5 重建会失败”的旧警告针对的是大容量机械硬盘,以及为什么该警告在 NVMe 上的适用性弱得多。负载方面的结论适用于任何介质。
通过 scrub 在重建前发现潜在错误。Debian 和 Ubuntu 都会为 md 阵列提供定期 scrub,但不同发行版的实现机制不同,因此应先确认当前系统使用哪种机制,然后手动触发一次检查。
systemctl list-timers --all | grep -i mdcheck
ls -l /etc/cron.d/mdadm
echo check | sudo tee /sys/block/md0/md/sync_action
cat /sys/block/md0/md/mismatch_cntsync_action 会在检查完成后返回 idle,而 mismatch_cnt 应显示为 0。镜像上的非零数值表示两半内容不一致。由于两个副本都没有校验和,内核无法判断哪个副本正确。有些不一致没有危害,交换分区是最常见的来源:内核可能正在写入某个页面,而该页面的内容同时发生了变化。数据阵列中的计数持续增加则表示应更换磁盘。
为什么 VPS 提供商在 NVMe 上统一采用 RAID 10
虚拟机管理程序节点不会只运行一种工作负载。它会运行数十个互不相关的客户机,其 I/O 以交错方式到达,表现为大量小写入,并且彼此之间没有局部性。这正是奇偶校验阵列的读-修改-写周期成本最高的场景,也是共享节点全天都会遇到的模式。
再考虑重建行为,选择就很明确了。奇偶校验节点上的一块磁盘发生故障时,整台主机上的每个客户机都会变慢数小时。RAID 10 节点上的一块磁盘发生故障时,只有对应的一对磁盘受到影响,数据会以磁盘速度顺序复制。提供商销售的是不会出现延迟尖峰的性能,因此会用容量换取这种性能:一半原始 NVMe 容量用于镜像。
磁盘容量的增长也推动了同样的选择。磁盘越大,重建窗口越长;对于奇偶校验阵列,这段时间内所有工作都会变慢,而且数据处于无保护状态。这也是虚拟化场景中的 ZFS 部署使用镜像 vdev 池,而不是宽 raidz 的原因:镜像 resilver 只需复制实际使用的块,并且只涉及一对磁盘。
这并不意味着 RAID 10 在所有场景下都正确。备份目标通常以长距离顺序写入,很少读取,因此 RAID 6 在那里更划算。它可以承受两块磁盘同时故障,并保留大部分容量。决定因素是工作负载,而不是磁盘数量。对于今天选择的方案,介质通常比其上的阵列布局更重要,而 从 SATA SSD 升级到 NVMe 带来的提升,大于两者采用任何 RAID 布局之间的差异。
如何读取 /proc/mdstat
请在您拥有该阵列的机器上执行这些命令,例如专用服务器、家用主机,或挂载了两个由您自行组建的卷的 VPS。请查看您自己的输出。下面的代码块是示例,已完整列出,便于您对照实际输出的结构。
cat /proc/mdstat
sudo mdadm --detail /dev/md0
lsblk -o NAME,SIZE,TYPE,MOUNTPOINTS健康的四盘 RAID 10 通常会输出类似内容。
Personalities : [raid1] [raid10]
md0 : active raid10 nvme3n1p3[3] nvme2n1p3[2] nvme1n1p3[1] nvme0n1p3[0]
3906764800 blocks super 1.2 512K chunks 2 near-copies [4/4] [UUUU]
bitmap: 0/30 pages [0KB], 65536KB chunk
unused devices: <none>其中每一部分都包含信息。
Personalities列出运行中内核已加载的 md 模块。这里出现raid10只表示相关代码可用,不代表其他含义。md0 : active raid10表示阵列设备、阵列状态和阵列级别。- 后面的名称是成员设备。方括号中的数字是设备在阵列元数据中的索引,不是它在该行中的位置,也不一定是它所在的插槽。
- 更换驱动器后,新成员通常会保留一个高于其所填补插槽的索引,因此
nvme4n1p3[4]可能位于插槽 2 中。mdadm --detail会在其RaidDevice列中输出实际插槽,因此两者不一致时应以该列为准。 - 成员后面的
(F)表示故障。(S)表示备用成员:设备已存在,但处于空闲状态,等待其他设备发生故障。 3906764800 blocks super 1.2表示可用容量,单位是 1 KiB 块,后面是元数据格式。512K chunks 2 near-copies表示条带块大小和 RAID 10 布局。此处的布局会将每个块的两个副本放在彼此相邻的位置。[4/4]先表示阵列期望的成员数量,再表示当前已同步的成员数量。[UUUU]为每个插槽输出一个字符,顺序与插槽顺序一致。U表示对应插槽已启用且已同步。_表示对应插槽中没有正常工作的设备。bitmap:是写入意图位图。它记录正在写入的区域,因此成员设备掉线后重新加入时,只需重新同步这些区域,而不是整个驱动器。
出现故障时,[4/3] 和 [UU_U] 的含义
降级阵列看起来如下。
md0 : active raid10 nvme3n1p3[3] nvme2n1p3[2](F) nvme1n1p3[1] nvme0n1p3[0]
3906764800 blocks super 1.2 512K chunks 2 near-copies [4/3] [UU_U]请同时查看这两个方括号。[4/3] 表示四个插槽中有一个未提供服务。[UU_U] 表示具体是哪一个,因为下划线是第三个字符,而插槽编号从零开始,所以插槽 2 已停止工作。只要故障驱动器仍连接在机器上,(F) 标志就会标识该设备。将驱动器从机器中拔出后,该名称会从该行消失,但下划线仍然存在。
阵列在这些情况下仍会继续提供服务。对于 RAID 10,性能通常接近满速,因此仅凭使用体验往往察觉不到故障。必须通过其他机制发现问题。
grep -i mailaddr /etc/mdadm/mdadm.conf
sudo mdadm --monitor --scan --oneshot --test
systemctl list-units --all | grep -i mdmdadm 软件包会安装一个监控守护进程。该进程从 /etc/mdadm/mdadm.conf 读取 MAILADDR。不同版本中的单元名称可能发生变化,因此请使用最后一条命令查找它,不要凭猜测填写名称。--test 运行后会立即为每个阵列发送一条消息。如果此后收件箱为空,表示邮件传递路径存在故障;您真正需要关注的告警也会以同样方式丢失。
更换驱动器正在重建时,阵列下方会出现进度行。
md0 : active raid10 nvme4n1p3[4] nvme3n1p3[3] nvme1n1p3[1] nvme0n1p3[0]
3906764800 blocks super 1.2 512K chunks 2 near-copies [4/3] [UU_U]
[==>..................] recovery = 12.4% (242012928/1953382400) finish=63.1min speed=452000K/secrecovery 表示正在将数据重建到替换驱动器。resync 表示对新建阵列执行的第一次一致性检查。check 表示您在上文触发的 scrub。括号中的数值表示进度,单位为 1 KiB 块,分母是单个设备的总块数;finish 是内核根据当前速度估算的剩余时间。重建速度受 /proc/sys/dev/raid/speed_limit_min 和 speed_limit_max 限制。设置这些上限是为了避免重建占满资源,影响生产 I/O。
重建期间执行完整 mdadm --detail
/dev/md0:
Version : 1.2
Creation Time : Tue Mar 10 09:14:22 2026
Raid Level : raid10
Array Size : 3906764800 (3.64 TiB 4.00 TB)
Used Dev Size : 1953382400 (1.82 TiB 2.00 TB)
Raid Devices : 4
Total Devices : 4
Persistence : Superblock is persistent
Update Time : Wed Aug 5 11:02:41 2026
State : clean, degraded, recovering
Active Devices : 3
Working Devices : 4
Failed Devices : 0
Spare Devices : 1
Layout : near=2
Chunk Size : 512K
Rebuild Status : 12% complete
Name : storage:0
Events : 4184
Number Major Minor RaidDevice State
0 259 3 0 active sync set-A /dev/nvme0n1p3
1 259 7 1 active sync set-B /dev/nvme1n1p3
4 259 11 2 spare rebuilding /dev/nvme4n1p3
3 259 15 3 active sync set-B /dev/nvme3n1p3Number 列是元数据索引,该索引会显示在 /proc/mdstat 的方括号中。RaidDevice 列是插槽,也就是 [UU_U] 字符串中的位置。这里两者不同,是因为设备 4 替换了原先位于插槽 2 的驱动器。set-A 和 set-B 表示每个镜像的两个部分。因此,在同一对中同时丢失 set-A 成员和 set-B 成员,且两者保存相同数据,是必须避免的情况。
在您拥有的阵列上更换驱动器需要执行四条命令,最后一条用于检查。
sudo mdadm --manage /dev/md0 --fail /dev/nvme2n1p3
sudo mdadm --manage /dev/md0 --remove /dev/nvme2n1p3
sudo mdadm --manage /dev/md0 --add /dev/nvme4n1p3
cat /proc/mdstat恢复行通常会在一两秒内出现。替换分区的大小必须至少与 mdadm --detail 中的 Used Dev Size 一样大。如果分区哪怕小一点,也会被拒绝,并显示类似 not large enough to join array 的消息。添加新驱动器前,请先将其分区调整为与旧驱动器一致。
从 VPS 内部可以看到和不能看到的内容
大多数客户无法看到宿主机的 RAID,这是设计如此。虚拟化管理程序会向您提供一个虚拟磁盘。该磁盘是从 NVMe 驱动器组成的 RAID 10 池中划分出来的,还是位于单个驱动器上,属于宿主机属性,在客户机内部不会显示。
systemd-detect-virt
lsblk -d -o NAME,SIZE,ROTA,MODEL
cat /proc/mdstatsystemd-detect-virt 在 KVM 客户机上输出 kvm,在容器上输出诸如 lxc 的容器类型,在裸机上输出 none。在 KVM 客户机上,您通常只能在 lsblk 中看到一个 vda 或 sda,并且在 /proc/mdstat 中看不到任何阵列,因为客户机内部不存在阵列。
在基于容器的 VPS 上,这个结果不可靠。容器共享宿主机内核,而 /proc 的部分内容没有进行命名空间隔离,因此其中显示的信息可能描述的是宿主机,而不是分配给您的存储切片。不要将其中任何信息视为您自己的存储事实。请向服务提供商询问存储布局;如果这对您很重要,请要求对方提供书面答复。
您可以在 VPS 内部检查分配给您的磁盘的实际行为。检查 VPS 磁盘是否确实为 NVMe介绍了能够报告真实信息的命令,SSD VPS 实际包含哪些内容介绍了套餐页面上的标签所代表的内容。
应在 VPS 内运行 RAID 吗?
通常不应这样做,原因在于故障域。如果将两个卷附加到一个 VPS,并使用 mdadm 将它们配置为镜像,这两个卷可能位于同一个物理阵列、同一个节点,并共用同一个电源。这样,您会为已有的冗余将每次写入的成本增加一倍,但对于真正关键的那种故障,两个副本仍会同时丢失。
如果服务提供商明确说明这些卷位于不同的故障域,或者您使用的是可以自行选择磁盘的专用服务器,那么这样做才有意义。否则,应优先将精力用于创建存放在本机之外的副本。
RAID 无法防护的情况
RAID 只能应对一种事件:磁盘停止正常工作。下面的操作都是有效写入,因此阵列会将其应用到每个副本,并报告自身状态正常。
- 删除。 在错误目录中执行
rm -rf,或部署脚本在路径中使用未设置的变量。阵列会将其视为合法写入,并执行两次。 - 勒索软件。 加密本身就是写入操作。正常工作的阵列会将加密后的版本存储在镜像的两端。
- 应用损坏。 会向数据库写入垃圾数据的 bug,也会将相同的垃圾数据写入冗余磁盘。
- 整个节点。 主机发生故障,或某个帐户被误暂停。阵列可以完全正常,但同时无法访问。
- 一周后的您自己。 您在星期一删除的文件,会在星期一从每个磁盘上消失。只有此前创建的副本才能将其恢复。
存储在同一存储设备上的快照也不是解决方案。它们可以帮助应对删除,但会随所在阵列一起失效。备份之所以是备份,关键在于它位于其他位置。使用 restic 创建加密的服务器外备份 是本页的另一部分:阵列让您能够在磁盘故障时继续提供服务,而当损坏来自阵列认为合法的写入时,restic 可以恢复您的数据。
FAQ
RAID 10 是否意味着我不需要备份?
不需要。RAID 10 只能防止磁盘停止工作。它会将每次有效写入同时应用到镜像的两侧,因此删除操作或勒索软件攻击也会在同一时间到达冗余磁盘。此后阵列仍会报告状态正常,因为从阵列的角度看没有发生故障。您仍然需要将副本存放在机器之外,也仍然需要偶尔执行恢复,以确认备份确实可用。
VPS 提供商为什么选择 RAID 10,而不是 RAID 5 或 RAID 6?
有两个原因,都与小块随机写入有关。奇偶校验写入需要先读回旧数据和旧奇偶校验,才能计算新的奇偶校验。因此,在 RAID 5 上,一次小写入需要 4 次操作,在 RAID 6 上需要 6 次,而镜像只需要 2 次。奇偶校验重建还需要从头到尾读取所有仍在工作的磁盘,这会让节点上的每个虚拟机都变慢数小时;RAID 10 重建则只需将一个磁盘复制到另一个磁盘,其他镜像对不受影响。代价是容量减少一半:原始 NVMe 容量只能使用一半。
/proc/mdstat 中的 [U_] 或 [UU_U] 表示什么?
每个字符按阵列中的槽位顺序表示一个槽位,每个槽位对应一个字符。U 表示该槽位包含一个已上线且已同步的成员。_ 表示该槽位中没有正常工作的成员。在一个双盘镜像中,[U_] 表示第二个槽位已停止工作,阵列不再具有冗余。请结合前面的成员数量信息一起读取,其中 [4/3] 表示阵列应有 4 个成员、当前有 3 个成员。槽位顺序与 mdadm --detail 的 RaidDevice 列一致,而不是与该行中设备名称出现的顺序一致。
RAID 10 阵列最多可以丢失多少块磁盘?
在任何故障分布下,至少可以丢失 1 块。超过这个数量后,结果取决于故障发生的位置。每个镜像对可以丢失其中一个成员,因此一个 8 盘阵列在没有两次故障落在同一个镜像对中的情况下,最多可以承受 4 次故障;如果两次故障都发生在同一个镜像对中,则发生 2 次故障时阵列就会失效。请按有保障的数量进行规划,即 1 块,并将超出这一数量的情况视为运气,而不是保护能力。
我应该使用 mdadm 在 VPS 内部镜像两个卷吗?
通常不应该。连接到同一个 VPS 的两个卷通常位于同一台主机上的同一个物理阵列中,因此镜像会使每次写入的成本翻倍,却无法防止主机自身 RAID 已经能够防止的任何故障。只有在提供商明确说明这两个卷位于不同故障域时,这样做才有价值。否则,应将精力投入到存放在机器之外的备份上。