简介
廉价冗余磁盘阵列(RAID,Redundant Array of Inexpensive Disks)使用多个磁盘共同构建更快、更大、更可靠的磁盘系统。
从外部看,RAID 对主机系统是透明的,表现为一个线性的块数组,就像一个大磁盘。这种透明性极大地提高了 RAID 的可部署性,无须修改操作系统和客户端应用程序即可直接替换原有磁盘。在内部,RAID 是一个复杂的专用计算机系统,包含微控制器、易失性内存(如 DRAM)、非易失性内存以及专用的奇偶校验逻辑电路。
故障模型与评估维度
为了理解和比较不同的 RAID 方法,我们假设使用故障—停止(fail-stop)故障模型。在该模型下,磁盘只有工作和故障两种状态。当磁盘发生故障时,数据永久丢失,且 RAID 控制器能立即检测到该故障。
评估每种 RAID 设计通常从以下三个维度进行:
- 容量:给定 N 个磁盘,客户端可用的有效容量。
- 可靠性:系统能够容忍的磁盘故障数量。
- 性能:分为单请求延迟和稳态吞吐量。稳态吞吐量主要在两种典型工作负载下评估:顺序(Sequential)和随机(Random)。假设单个磁盘的顺序吞吐量为 S,随机吞吐量为 R。
RAID 0 级:条带化
RAID-0 不提供冗余,通过将块在磁盘上轮转分布(条带化,Striping)来最大化并行性。
以 4 个磁盘为例,块按如下方式分布:
| 磁盘 0 | 磁盘 1 | 磁盘 2 | 磁盘 3 |
|---|---|---|---|
| 0 | 1 | 2 | 3 |
| 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 |
同一行中的块称为一个条带(stripe),例如块 0、1、2、3 在同一条带中。给定逻辑块地址 A,可以通过以下公式计算其物理位置:
磁盘 = A % 磁盘数
偏移量 = A / 磁盘数 (整数除法)大块大小(Chunk Size)
大块大小是指在移动到下一个磁盘之前,在单个磁盘上连续放置的数据量。大块大小主要影响性能:
- 较小的大块:单个文件跨多个磁盘条带化,增加了单文件读写的并行性,但整个请求的定位时间由所有驱动器上的最大定位时间决定,会有所增加。
- 较大的大块:减少了文件内的并行性,但降低了定位时间(文件可能只需访问单个磁盘)。
确定最佳大块大小需要大量关于工作负载的知识,实践中大多数阵列使用 64KB 左右的大块大小。
性能分析
- 容量:N
- 可靠性:0(任何磁盘故障都会导致数据丢失)
- 吞吐量:顺序读写 N·S,随机读写 N·R
- 延迟:读 T,写 T(请求直接重定向到单个磁盘,与单磁盘延迟相同)
RAID-0 是性能和容量的上限,是与其他 RAID 级别比较的基准。
RAID 1 级:镜像
RAID-1 通过为每个逻辑块保留多个物理副本(通常为两个)来提供冗余,数据在镜像对之间条带化。
| 磁盘 0 | 磁盘 1 | 磁盘 2 | 磁盘 3 |
|---|---|---|---|
| 0 | 0 | 1 | 1 |
| 2 | 2 | 3 | 3 |
| 4 | 4 | 5 | 5 |
| 6 | 6 | 7 | 7 |
磁盘 0 和磁盘 1 互为镜像,磁盘 2 和磁盘 3 互为镜像。这种布局有时称为 RAID-10(RAID 1+0),即先镜像再条带化。另一种常见布局是 RAID-01(RAID 0+1),即先条带化再镜像。
读取时,RAID 可以从任一副本读取,可以利用所有磁盘。写入时,必须同时更新两个副本,两次写入可以并行进行。
一致更新问题
在更新多个磁盘时,如果写入期间发生掉电,可能导致两个副本不一致(一个是新版本,另一个是旧版本)。解决方法是使用预写日志(Write-ahead log),在实际写入前先记录操作。大多数 RAID 硬件通过少量电池备份的非易失性 RAM 来实现,避免了将日志写入磁盘的高昂代价。
性能分析
- 容量:N/2
- 可靠性:至少容忍 1 个磁盘故障,最多可容忍 N/2 个(取决于故障磁盘的分布)
- 吞吐量:
- 顺序读写:(N/2)·S。顺序读取时,为了保持数据顺序,每个磁盘只能处理每隔一个的块请求,在跳过的块上空转,因此只能达到峰值带宽的一半。
- 随机读:N·R(可将读请求分布在所有磁盘上)
- 随机写:(N/2)·R(每次逻辑写入变为两次物理写入)
- 延迟:读 T,写 T(写入时两个物理写入并行,但延迟略高于单磁盘,因受限于两次写入中最差的寻道和旋转延迟)
RAID 4 级:通过奇偶校验节省空间
RAID-4 使用一个专用的奇偶校验(Parity)磁盘存储冗余信息,以较少的容量损失来换取可靠性。
注意:由于奇偶校验本质上只提供了一个数学方程(偶数规则),因此 RAID-4(以及基于相同原理的 RAID-5)最多只能容忍 1 块硬盘发生故障。如果同时损坏 2 块盘,将出现两个未知数,数据将无法恢复。
| 磁盘 0 | 磁盘 1 | 磁盘 2 | 磁盘 3 | 磁盘 4(奇偶) |
|---|---|---|---|---|
| 0 | 1 | 2 | 3 | P0 |
| 4 | 5 | 6 | 7 | P1 |
| 8 | 9 | 10 | 11 | P2 |
| 12 | 13 | 14 | 15 | P3 |
奇偶校验原理(XOR)
RAID-4 本质上是对所有数据盘的同一个位置(每一位)进行对齐计算,生成一个同样大小的校验块。通过异或(XOR)运算,系统强制要求同一行所有盘(包括校验盘)在相同位置的 1 的总数始终为偶数:
| C0 | C1 | C2 | C3 | P (校验位) |
|---|---|---|---|---|
| 00 | 10 | 11 | 10 | 11 |
| 10 | 01 | 00 | 01 | 10 |
- P0(11): 第1列两个1补1,第2列一个1补1,结果为11
- P1(10): 第1列一个1补1,第2列两个1补0,结果为10
数据恢复:当硬件报错提示某块盘物理损坏时,RAID 控制器只需读取剩余盘和校验盘的对应位。根据“总数必须是偶数”的规则,就能完美反推出丢失位置的 0 或 1。对于 4KB 的数据块,则是对块中每个比特位批量执行此操作。
写入方式
全条带写入(full-stripe write):当一次性写满一整行(所有数据盘)时,RAID-4 可直接算出新的校验块并一起写入。这是最高效的写入方式,顺序写入吞吐量可达 (N-1)·S。
小写入问题(small-write problem):当只修改条带中的一小块数据时,为了维持“偶数规则”,必须同步修改校验块。这需要使用 减法奇偶校验(subtractive parity) 方法:
- 读取旧数据块(C_old)和旧奇偶校验块(P_old)
- 计算新奇偶校验:
- 将新数据块和新奇偶校验块写入磁盘
每次小写入需要 4 次物理 I/O(2 次读 + 2 次写)。更致命的是,任何数据盘的修改都必须排队去更新那块唯一的校验盘。这导致校验盘成为全局的“单点瓶颈”,使得随机写入操作被迫序列化。
性能分析
- 容量:N - 1
- 可靠性:1
- 吞吐量:
- 顺序读写:(N-1)·S
- 随机读:(N-1)·R
- 随机写:(1/2)·R(奇偶校验磁盘每个逻辑 I/O 需执行 2 次 I/O,成为瓶颈)
- 延迟:读 T,写 2T(先并行读旧数据和旧奇偶,再并行写新数据和新奇偶)
RAID 5 级:旋转奇偶校验
RAID-5 与 RAID-4 的工作原理基本相同,唯一的区别是将奇偶校验块跨所有驱动器旋转分布,从而消除了专用奇偶校验磁盘的瓶颈。
| 磁盘 0 | 磁盘 1 | 磁盘 2 | 磁盘 3 | 磁盘 4 |
|---|---|---|---|---|
| 0 | 1 | 2 | 3 | P0 |
| 5 | 6 | 7 | P1 | 4 |
| 10 | 11 | P2 | 8 | 9 |
| 15 | P3 | 12 | 13 | 14 |
| P4 | 16 | 17 | 18 | 19 |
每个条带的奇偶校验块轮流放置在不同的磁盘上,使得多个并发写入请求可以访问不同磁盘上的奇偶校验块,从而实现并行。
为什么能实现并行?
在 RAID-4 中,所有写入操作都必须访问同一块固定的校验盘(如磁盘 4),导致物理磁头冲突,只能排队串行。而在 RAID-5 中,校验块被打散。例如,同时写入块 1 和块 10 时:
- 写入块 1 需要占用 磁盘 1(数据)和 磁盘 4(校验块 P0)。
- 写入块 10 需要占用 磁盘 0(数据)和 磁盘 2(校验块 P2)。 两组操作需要的物理磁盘完全没有交集,因此可以同时读写,真正实现了并发。
性能分析
- 容量:N - 1(与 RAID-4 相同)
- 可靠性:1(与 RAID-4 相同)
- 吞吐量:
- 顺序读写:(N-1)·S(与 RAID-4 相同)
- 随机读:N·R(所有磁盘均可参与读取,比 RAID-4 略好)
- 随机写:(N/4)·R(消除了单盘瓶颈,但每次写入仍需 4 次 I/O)
- 延迟:读 T,写 2T(与 RAID-4 相同)
由于 RAID-5 在几乎所有情况下都优于或等于 RAID-4,它已基本取代了市场上的 RAID-4。唯一例外是系统确定只会执行顺序大写入的场景,此时 RAID-4 因构建稍简单而偶有使用。
总结
各级 RAID 的核心特征对比(假设单盘请求延迟为 T):
| 指标 | RAID-0 | RAID-1 | RAID-4 | RAID-5 |
|---|---|---|---|---|
| 容量 | N | N/2 | N - 1 | N - 1 |
| 可靠性 | 0 | 1(肯定),N/2(运气好) | 1 | 1 |
| 顺序读 | N·S | (N/2)·S | (N-1)·S | (N-1)·S |
| 顺序写 | N·S | (N/2)·S | (N-1)·S | (N-1)·S |
| 随机读 | N·R | N·R | (N-1)·R | N·R |
| 随机写 | N·R | (N/2)·R | (1/2)·R | (N/4)·R |
| 读延迟 | T | T | T | T |
| 写延迟 | T | T | 2T | 2T |
选择 RAID 级别取决于最终需求:
- 追求极致性能且不关心可靠性:选择 RAID-0。
- 需要随机 I/O 性能和高可靠性,且能接受容量减半:选择 RAID-1。
- 追求容量和可靠性最大化,且以顺序 I/O 为主:选择 RAID-5。
- 工作负载以顺序大写入为主且希望简化实现:可考虑 RAID-4。