S2D(Storage Spaces Direct)的 chunk mapping(数据块映射),本质是它整个分布式存储系统的"核心地址系统"。你可以把它理解为:
把一个虚拟磁盘(VHDX/CSV 卷)中的逻辑数据块,映射到集群中所有物理磁盘上的"分布式坐标系统"。
一、先给结论:S2D 的 chunk mapping 是什么?
S2D 使用的是一种:虚拟化分层映射结构(Virtualized Extent-Based Mapping)
核心结构:
Volume (CSVFS)
↓
Storage Spaces Virtual Disk
↓
Slab / Chunk Mapping Table(核心)
↓
Extents(逻辑块)
↓
Physical Disk + Fault Domain
详细描述:
- CSVFS(Cluster Shared Volume File System) 是 S2D 最常用的接入层,但它本身不负责"块在哪"。CSV 只解决"多个节点同时挂载同一个卷、并发访问不冲突",把 I/O 重定向到协调节点(coordinator node)。也就是说,S2D 的"地址"在 CSV 之下,不在 CSV 之上。
- 这个分层的好处是:上层的 NTFS、应用程序、Hyper-V 看到的还是普通块设备(VHDX/CSV),完全感知不到底下是几十块 NVMe 还是混插的 HDD+SSD。
- Virtual Disk 这一层是 S2D 自己抽象出来的"逻辑盘",对应
Get-VirtualDisk的对象。Slab/Chunk Mapping Table 是 S2D 内部维护的"私货",对外不可见。
二、S2D 的"Chunk"到底是什么?
在 S2D 中,"chunk"通常指:固定大小的逻辑分配单元(Extent / Slab)。
典型粒度:
- 1 GB(常见 slab size)
- 或更细粒度 extent
⚠️ 注意:它不是 RAID stripe unit,而是虚拟存储分配单位。
详细描述:
- Slab 是 S2D 里的"分配单位"(allocation unit)。一个 Virtual Disk 会被切成很多个 Slab,每个 Slab 独立决定副本策略、独立做故障恢复。所以 Slab 不能太小(否则映射表爆炸),也不能太大(否则小文件浪费空间)。1 GB 是 S2D 的默认值,也是工业界共识。
- Extent 在 S2D 内部文档里更接近"chunk",是 S2D 内部用于 I/O 调度的更小单位。一个 Slab 由若干个 Extent 组成,Extent 的粒度通常和存储总线/扇区对齐,常见 256 KB 或 1 MB。
- Slab ≠ Stripe Unit。RAID-5/6 的 stripe unit 决定的是"一次写跨几个盘、校验块放哪";S2D 的 Slab 决定的是"一段连续逻辑地址放哪几个盘",不参与条带打散(S2D 的 parity 是按 Slab 分组的,而不是按字节条带)。
- 还有一个容易混淆的概念是"interleave",是 S2D Virtual Disk 的一个属性,描述"一次 I/O 跨多少块物理盘"做并行写入。Interleave 和 Slab 是两个正交的东西,一个管"扇区怎么散",一个管"块放哪里"。
三、核心结构:三层映射模型
S2D chunk mapping 不是一层,而是三层结构:
1️⃣ 第一层:虚拟卷 → Extent(逻辑层)
例如:
VHDX / CSV Volume
↓
Logical Block Address (LBA)
被切分为:
- 1 MB / 256 KB(I/O 粒度)
- 汇聚成 extents(逻辑连续块)
2️⃣ 第二层:Extent → Slab(S2D 核心)
这是关键层:Slab = S2D 的分配与调度单位
每个 slab:
- 大小通常为 1 GB
- 属于某个虚拟磁盘(VDisk)
- 绑定副本策略(mirror / parity)
映射表:Slab ID → {Disk1, Disk7, Disk12}
- 2-way mirror → 2 个物理位置
- 3-way mirror → 3 个物理位置
- Parity(单奇偶)→ 1 数据 + 1 校验(多盘)
- 双奇偶 → 1 数据 + 2 校验
3️⃣ 第三层:Slab → Physical Disk Extent
最终落到:
-
NVMe / SSD / HDD
-
具体 offset(物理地址)
Slab
↓
Physical Extent
↓
Disk sector address
详细描述:
- LBA 到 Extent 的切分取决于两个东西:底层磁盘的"physical sector size"(S2D 默认按 4 KB 对齐,但如果是高级格式 512e 也会兼容),以及
Get-VirtualDisk | Get-StorageTier的 Interleave 属性。 - Mirror 和 Parity 是 Per-Slab 策略。这意味着同一个 VDisk 里,可以有"前面 100 GB 是三副本,后面 1 TB 是双副本"------实际生产中很少这么用,但能力是具备的。
- 副本 / 校验的具体盘不是 Slab 内部决定的,而是由 S2D 的 placement 算法 决定的。Slab 表格里只记录"放哪了",不记录"为什么放那"。
- Sector address 落到磁盘时,S2D 还会再走一层"physical disk 的 sector 偏移"。如果你的盘是分区过的(partitioned),S2D 会自动避开分区表所在区域,避免把元数据写到分区头。
四、S2D Chunk Mapping 的核心数据结构
内部维护一个关键结构:Mapping Table(类似分布式 FAT / inode)
| 字段 | 含义 |
|---|---|
| Slab ID | 逻辑块编号 |
| Policy | mirror / parity |
| Fault Domain | 节点 / 机架 |
| Disk list | 实际存储位置 |
| Offset | 物理位置 |
| Health state | 是否降级 |
详解描述:
- 这张表在 S2D 里叫 "allocation map" 或 "slab allocation map",由 Cluster Service(ClusSvc) 统一管理,不会 单独存在某一个节点上。它通过集群注册表 / 分布式协调(类似 Raft 思路)保持一致。所以即使一个节点掉电,这张表也不会丢。
- Health state 至少包含:
Healthy/Degraded(一个副本丢了)/Shrinking(正在回收)/InRepair(正在重建)。Get-VirtualDisk | Get-StorageReliabilityCounter能看到一部分。 - Disk list 不是写死的------它会随时间漂移。系统会周期性调用"rebalancer",根据当前 IO 热度、容量、故障域分布,悄悄 调整某些 Slab 的位置(业内叫 slab rebalancing )。这意味着你在两台机器上跑
Get-PhysicalDisk | Get-StorageReliabilityCounter看到的"在某盘上分配了多少"会变化。 - 没写进表的内容:S2D 的 mapping table 里不存数据本身(这是显然的),也不存文件路径 / 文件名。文件级元数据归 NTFS / ReFS 管;chunk mapping 只管"盘上的字节属于哪一块逻辑地址"。
五、一个真实写入示例
假设:
- 2-way mirror
- 3 节点集群(Node A / B / C)
- 写入一个 4 MB 文件
Step 1:切块 4 MB → 4 × 1 MB extents
Step 2:分配 slab
| Extent | Slab |
|---|---|
| E1 | S1001 |
| E2 | S1002 |
| E3 | S1003 |
| E4 | S1004 |
Step 3:映射到物理磁盘(chunk mapping)
S1001:Primary: Node A / NVMe0 Replica: Node B / NVMe1
S1002:Primary: Node B Replica: Node C
S1003:Primary: Node C Replica: Node A
Step 4:写入路径
App write
↓
CSVFS
↓
SBL (Storage Bus Layer)
↓
Chunk mapping lookup
↓
Parallel write to disks
详细描述:
- SBL(Storage Bus Layer) 是 S2D 内核态的核心组件,它把"逻辑 I/O"翻译成"对 Physical Disk 的具体 I/O 请求"。如果把整个 S2D 比作一个数据库,SBL 就是"执行引擎"。
- CSVFS 的协调节点(coordinator) 不一定和 Primary 节点一致。比如应用跑在 Node A,Node A 是 coordinator,I/O 被 forward 到 Node B(B 才是 Slab S1001 的 Primary 之一)。S2D 不要求"写主本必须走 Primary 节点",这是它和某些 SAN 协议不一样的地方。
- 写盘顺序:mirror 模式下 S2D 默认不是同步双写,而是 "write-back cache + 异步同步"。如果开了 Storage Bus Cache(混插 S2D 里的"性能层"),数据会先写 SSD cache,再 async 落 HDD。这对延迟很敏感的应用(SQL Server 事务日志、Hyper-V VHDX runtime)是关键。
- 写穿(write-through)模式:如果你用纯 NVMe 全闪 S2D(没有混合层),行为退化为"两份都落盘才返回成功",延迟更稳但 RT 更高。
- Parity 写入比 Mirror 复杂得多。Parity 模式下 S2D 还要做"读改写"(read-modify-write)和"重组"(reconstruct write)。一次 4 KB 写入可能涉及读出整个 stripe(几 MB)、计算新校验、写回。这是 S2D Parity 比 Mirror 慢几十倍的根本原因。
六、S2D Chunk Mapping 的关键特性
1️⃣ 动态分布(Dynamic Placement)
不固定 RAID stripe,每个 slab 可在任何磁盘。 类似 Ceph CRUSH,但微软实现。
2️⃣ 故障域感知(Fault Domain Awareness)
mapping 会避免:同一节点、同一机架放同一副本。
3️⃣ 自动重建(Rebalance)
当:新加节点 / 磁盘失效 时,系统会 Re-map slabs → 重新分布。
4️⃣ 负载均衡(IO aware placement)
不是只看容量,还看:IO 热度、latency、queue depth。
详细描述:
- 故障域(Fault Domain, FD) 不仅是节点和机架。在 Azure Stack HCI 里,FD 还能细到"机箱(chassis)"、"机柜顶(rack top)"、"电源回路"。
Get-ClusterFaultDomain可以看完整层级。一个 3-way mirror 的副本一定落在 3 个互不重叠的故障域里。 - Rebalance 不是瞬间完成。新加节点后,
Start-StorageReliabilityCounter或 storage job 会在后台慢慢搬 slab,速率被限流(避免影响业务 IO),整个池可能要几小时到几天才完全 rebalance 完。期间性能会有抖动。 - 磁盘失效 vs 节点失效 的处理路径不一样:
- 单盘坏:S2D 触发 "Repair" job,按 Slab 重建坏的那个副本。
- 整机掉:cluster 先仲裁(quorum)------超过半数节点在线才继续服务;只要还能保持 quorum,受影响 Slab 进入"degraded + awaiting repair",修复由剩余节点上的副本承担。
- 仲裁丢失:所有 Slab 暂时停服。这是为什么 S2D 集群推荐 2N+1 节点(容忍 1 节点挂)而不是 2N。
- IO 感知的再分布 在 S2D 里叫 "Storage Aware Placement",但它不是实时的。是后台周期任务,间隔几十分钟到几小时。所以你会看到"刚加完节点,第一天没动静,第二天才看到磁盘读写开始迁移"这种现象。
七、Chunk Mapping vs RAID
| 特性 | S2D Chunk Mapping | RAID |
|---|---|---|
| 单位 | slab (1 GB) | stripe unit |
| 管理方式 | 分布式映射表 | 控制器固定 |
| 扩展性 | 线性扩展 | 有上限 |
| 重建 | slab 级别 | disk 级别 |
| 故障域 | 节点级 | 磁盘级 |
详细描述:
- 扩展性 这一点是 S2D 的最大卖点。传统硬件 RAID 控制器有最大盘数限制(一般 16-32),且性能随盘数非线性增长(控制器是瓶颈)。S2D 因为 placement 在软件层做,且分布到所有节点,能扩展到 4 节点 / 16 节点 / 64 节点(Azure Stack HCI 单集群上限)。
- RAID 的"重建"是替换整盘------换了新盘,控制器把整盘数据按 stripe 顺序重新算出来写回去。S2D 的"重建"是按 Slab 重建------只重建那些"副本数不足"的 Slab,其他 Slab 根本不需要动。所以 S2D 重建时 IO 影响远比 RAID 小(且是后台限流的)。
- RAID 没有"故障域"概念,它的"冗余度"是盘级别的。S2D 故障域是节点/机架级------这意味着即使坏一块盘,cluster 还会照常服务;即使坏一个节点,剩下的节点会接手所有该节点上的 slab 重映射。这就是 S2D 能"在线换节点"的原因。
- RAID 5 的写入惩罚(write penalty) 在 S2D Parity 上也存在,但 S2D 通过全闪性能层 + 写回 cache 缓解。
- 一句话总结:S2D 把"RAID 卡"做的事情,抽到了分布式软件层,且粒度从"盘"降到了"slab"。
八、一个关键理解
S2D chunk mapping 本质不是"存储结构",而是:一个分布式一致性"数据地址系统"(Distributed Storage Addressing Layer)
它同时负责:
- 数据放哪里
- 副本在哪
- 如何恢复
- 如何迁移
- 如何负载均衡
详细描述:
- "分布式一致性" 是关键词------S2D 的 mapping table 是集群范围内一致的,这和"每台机器各管各的 RAID"有本质区别。任何一次 slab 迁移、任何一次副本重分配,都需要集群所有节点达成一致。
- "地址系统" 而不是 "存储系统"------注意区分。S2D 的 mapping 只管"地址 → 物理位置",不管"这些位置上放的是什么字节"。"字节"本身由底层 Physical Disk 负责,文件结构由 NTFS / ReFS 负责。
- 它同时是五件事:placement(放置)、replication(复制)、repair(恢复)、migration(迁移)、balancing(均衡)。传统存储系统通常只能做其中一两件;S2D 把它打包成一张"统一表",是它能像超融合一样灵活的根本原因。
- 类比真实分布式系统:S2D 的 chunk mapping 接近 Ceph 的 OSD map + PG map 的合体,但比 Ceph 简单(Ceph 的 CRUSH 算法有显式权重 / 拓扑规则,S2D 是内部启发式);也类似 HDFS 的 NameNode 元数据,但 NameNode 是单点,S2D 是分布式共识。
九、类比
| 系统 | 类比 |
|---|---|
| RAID | 单机数组 |
| NTFS 文件系统 | inode |
| S2D chunk mapping | 分布式 inode + 路由表 |
| Ceph CRUSH | 同类系统(但更显式算法) |
详细描述:
- 和 Ceph 的更精确对比:
- Ceph PG ≈ S2D Slab(都是分配单位)
- Ceph OSD ≈ S2D Physical Disk
- Ceph OSD Map / CRUSH Map ≈ S2D Fault Domain 配置
- Ceph Pool ≈ S2D Storage Pool / Virtual Disk
- 核心区别:Ceph 显式分离"OSD Map(盘在不在)+ CRUSH Map(怎么放)+ PG Map(数据归谁)"三张表;S2D 把它合并成一张 distributed mapping table。这是 S2D 部署更简单、但精细控制不如 Ceph 的原因。
- 和传统 SAN 的对比:传统 SAN(NetApp / VMware vSAN / 华为 OceanStor)的"地址系统"通常叫 LUN Mapping / VMFS Metadata------它们基本是"控制器单点决策 + 客户端缓存"模型,扩到几十节点就吃力。S2D 是端到端分布式决策,这是它能跑超融合的根本。
- 建立直觉的最快方式:把 S2D 想象成"每块盘都自己是一台小 Ceph OSD",而 chunk mapping 就是这些 OSD 共同维护的"分布式大脑"。