142 / 163 · C11 · 约 8 分钟
廉价磁盘冗余阵列(RAID)
先记住这句话
RAID通过将多块廉价磁盘组织成阵列,在保持对主机系统完全透明的前提下同时提升容量、吞吐和容错能力。本章介绍其对外接口、故障假设、三维评估方法以及最基础的条带化组织。
动机与透明部署
单盘在速度、空间和寿命上都容易成为瓶颈。把多块磁盘当作一个整体来用,既能并行服务请求,又能提供更大的连续地址空间,还能靠冗余挡住个别磁盘损坏。最关键的一点是这种整体对外看起来仍然只是一块普通磁盘,因此操作系统和应用程序一行代码都不用改就能立刻受益。
对外接口与控制器内部
上层文件系统只看见一个线性块数组,发出逻辑读写即可。控制器负责把每个逻辑请求翻译成一次或多次物理磁盘操作,并维护必要的缓冲与校验计算。硬件实现通常自带微处理器、易失与非易失内存以及专用校验引擎,本质上就是一台专门跑存储固件的计算机。
故障假设与三维评估
当前采用最简单的故障-停止模型:磁盘要么完全正常,要么彻底丢失,并且丢失立刻可被控制器察觉。任何具体方案都从三个互相制约的维度衡量:客户端真正可用的容量、能够同时承受的磁盘失效个数、以及在顺序与随机两类负载下的实际带宽与延迟。
RAID-0 条带化组织
最朴素的做法是把连续逻辑块轮流放到各块磁盘上,既不浪费空间也不引入冗余。同一“行”上的块构成一条带,一次大顺序读可以同时启动所有磁盘。块组大小(chunk)决定了切换磁盘前在同一盘上连续放置多少块,从而在小随机请求与大顺序请求之间取得折中。
常见误区
- 只计算总容量而忽略具体负载下的并行度差异
- 把故障模型简化成“整盘立刻可检测”,从而忽视静默损坏
运行一个例子
最低标准 C11 · 完整程序 · 下载 .c
#include <stdio.h>
int main(void) {
const int N = 4;
const int C = 1;
printf("RAID Level 0 mapping for first 16 logical blocks\n");
for (int lb = 0; lb < 16; lb++) {
int d = (lb / C) % N;
int off = (lb / (N * C)) * C + (lb % C);
printf("LB %2d maps to disk %d offset %d\n", lb, d, off);
}
return 0;
}
在本地编译
gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-38-raid.c -o example && ./example预期结果
RAID Level 0 mapping for first 16 logical blocks
LB 0 maps to disk 0 offset 0
LB 1 maps to disk 1 offset 0
LB 2 maps to disk 2 offset 0
LB 3 maps to disk 3 offset 0
LB 4 maps to disk 0 offset 1
LB 5 maps to disk 1 offset 1
LB 6 maps to disk 2 offset 1
LB 7 maps to disk 3 offset 1
LB 8 maps to disk 0 offset 2
LB 9 maps to disk 1 offset 2
LB 10 maps to disk 2 offset 2
LB 11 maps to disk 3 offset 2
LB 12 maps to disk 0 offset 3
LB 13 maps to disk 1 offset 3
LB 14 maps to disk 2 offset 3
LB 15 maps to disk 3 offset 3
CHECK YOUR UNDERSTANDING
合上答案,试着解释。
4盘 RAID-0、chunk=1 时,逻辑块 11 落在哪一块磁盘的哪个偏移上?
查看参考答案
磁盘 3、偏移 2。因为 11÷1 后对 4 取模得 3,整除 4 后得偏移 2。
继续查证
标准草案与官方章节会更新;版本标记只说明示例最低要求。