fastblock:基于 SPDK 与 Multi-Raft 的全闪存分布式块存储
【免费下载链接】fastblockA distributed block storage system that uses mature Raft protocol and is designed for all-flash scenarios项目地址: https://gitcode.com/openeuler/fastblock
fastblock 是 openEuler 社区开源的分布式块存储系统,使用 SPDK 用户态框架构建,数据复制依赖成熟的 Raft 协议,面向全闪存(NVMe 磁盘 + RDMA 网络)场景设计。本文回答几个实际问题:它的组件如何分工、PG 对应的多 Raft 复制与心跳合并是怎么做的、没有 RDMA 网卡时如何先跑通最小集群,以及不同副本配置下如何解读 IOPS 与延迟指标。
fastblock 要解决什么问题:传统块存储的五个短板
fastblock 的定位来自对 Ceph 等主流分布式块存储在全闪存场景下五类短板的针对性改进(来自项目 README 的归纳):
| 维度 | 现有体系中的问题 |
|---|---|
| CPU 经济性 | NVMe SSD 集群中 CPU 成为瓶颈,消耗偏高 |
| 可用性 | 主从强同步复制下,集群抖动时 IO 会被挂起 |
| 单卷性能 | 对接 QEMU 时进一步下降,需要多个卷才能跑满集群 |
| 单卷延迟 | 未能发挥 NVMe 低延迟特性,RBD 块设备常处于毫秒级 |
| 并发总量 | IOPS 与吞吐距硬件可提供的水平差距较大 |
对应的四条设计选择是:用 SPDK 的用户态 NVMe 驱动与无锁队列缩短 IO 路径;引入 RDMA 网卡做零拷贝、内核旁路、不需要 CPU 干预的网络通信;采用 multi-raft 做数据复制,每个 PG(放置组)对应一个独立 Raft 组;元数据管理保持简单、可靠、可定制。
💡 ## 如何理解 fastblock 的三层分工:从 Compute 到 localstore
整体架构沿用了 Monitor、OSD、PG 这类 Ceph 概念,降低已有背景读者的理解成本。系统分为计算接入、Monitor 集群、存储集群三层,数据与元数据走不同的链路。
Monitor:为什么元数据用 Golang 和 etcd
Monitor 集群维护 OSDMap、PGMap、Pool 与 Image 信息,处理节点加入/删除、卷元数据、创建 pool 以及按拓扑在 OSD 上均匀放置 Raft 组。它不存用户数据、不追求极致性能,所以用 Golang 实现,并用 etcd 做多副本存储。客户端和每个 OSD 启动后都会开启定时器,周期性向 Monitor 拉取 osdmap/pgmap,因此所有节点看到的是同一份集群视图;客户端 IO 只看到 PG 这一层,对特定 PG 的写入不会落到错误的位置。
OSD:数据面与元数据面分离
OSD(Object Storage Daemon)是存储核心,每个 Storage Node 上运行多个 OSD 实例。OSD 内部又分为 RPC 子系统、Raft 子系统、本地存储引擎(localstore)和 kv 子系统。
RPC 子系统按异构网络思路设计,三类消息走两套传输:
| RPC 类型 | 路径与用途 | 传输方式 |
|---|---|---|
| Control RPC | 客户端/OSD 与 Monitor 之间传 osdmap、pgmap、image 信息 | TCP socket |
| Data RPC | 客户端与 OSD 之间传对象数据与结果 | protobuf + RDMA |
| Raft RPC | OSD 之间传 Raft 协议消息(内含对象数据) | protobuf + RDMA |
元数据量小、频率低,socket 足够;对象数据量大、频率高,交给 RDMA 异步语义(RDMA write)承载。
🔁 ## Multi-Raft 的心跳合并:复制多了为什么不卡
每个 PG 对应一个 Raft 组,集群中大量 Raft 组并存。每个组的 leader 都要向 follower 发心跳,组数一多,心跳包就会挤占带宽和 CPU。fastblock 的合并机制是:同一对 leader/follower 之间属于多个 PG 的心跳合并成一个包再发。例如 pg1 和 pg2 都包含 osd1、osd2、osd3 且 osd1 是 leader,未合并时 osd1 要分别向 osd2、osd3 发两次心跳;合并后只需各发一次携带 (pg1, pg2) 的心跳。
Raft 子系统整体还包含:Raft 组的创建/修改/删除、选举与选举超时处理、log 的缓存/落盘/复制到 follower、数据 state machine 落盘、快照管理与 log 恢复、成员变更管理,参考了 willemt 的 C 语言 Raft 实现并扩展出 multi-raft。
本地存储引擎 localstore 基于 SPDK Blobstore,分三个模块:
- disk_log:存 Raft log,一个 PG(一个 Raft 组)对应一个 SPDK Blob;
- object_store:存对象数据,一个对象对应一个 Blob;
- kv_store:每个 CPU 核一个 Blob,存放该核上需要持久化的 kv 数据。
配套的 kv 子系统用于存 Raft 元数据和系统自身数据:数据量不大,内存 hash map 即可容纳全部数据,对外提供 put、remove、get 接口,每 10ms 把变更写盘。
客户端接入方式怎么选:vhost、NBD、CSI
客户端负责创建、修改、删除 image,把用户对 image 的操作转换为对 object(OSD 处理的基本数据单元)的操作,封装成 Data RPC 发给对应 PG 的 leader OSD,再处理返回的响应。接入方式有三种:
- SPDK vhost:面向虚拟机(QEMU);
- NBD:面向裸金属服务器;
- CSI:面向容器环境。
三种模式最终都经由 libfastblock 库完成 image 到 object 的转换并与 OSD 通信。以 vhost 为例,流程是:启动 fastblock-vhost(一个 SPDK 应用,内置定时器周期性向 Monitor 拉取 osdmap/pgmap/image 信息)→ 用 SPDK 的 rpc.py 发送 bdev_fastblock_create 请求创建 image 与 bdev 设备 → 再发 vhost_create_blk_controller 请求,打开设备并注册 vhost 驱动,创建可供 QEMU 连接的 socket → QEMU 通过 vhost-user-blk 设备挂接后,数据请求即由 libfastblock 路由到 leader OSD。
🖥 ## 没有 RDMA 网卡时如何先跑通最小集群
源码可通过git clone https://gitcode.com/openeuler/fastblock获取。编译侧需要安装依赖后分别构建 Monitor 与 OSD(./install-deps.sh,./build.sh -t Release -c monitor与./build.sh -t Release -c osd),再到 build 目录make install。
跑测试环境不强制依赖真实 RDMA 网卡和 NVMe 盘:vstart.sh 的 dev 模式会利用内核模块 rdma_rxe 创建虚拟 RDMA 网卡、用本地文件做 OSD 后端,在单机搭出 3 个 OSD、三副本的集群并自动创建默认 pool。命令只需一行:
./vstart.sh -m dev -c 3 -r 3 -C 2其中-C指定每个 OSD 占用的核数,建集群时指定后不可再改;运行前需要预留足够的 hugepage。拉起后建议先做状态验证:
fastblock-client -op=status后续排查 PG 映射、OSD 状态、建池可用-op=getpgmap、-op=getosdmap、-op=createpool等参数。多机生产部署则切换 pro 模式,分别指定 Monitor IP、RDMA 网卡名与 NVMe 盘,具体参数以 vstart.sh 脚本头部的注释说明为准。
📊 ## 三副本配置下如何看 IOPS 与延迟指标
项目 2024-12 的性能测试报告使用 Kunpeng-920 96 核、100Gb/s 网卡、4K 写、队列深度 32,且所有副本都在同一台测试机上。素材给出的代表数据:
| 场景 | 工具 | IOPS | p999 延迟 |
|---|---|---|---|
| 1 个 OSD、单副本 | block_bench | 约 35.8 万 | 约 419us |
| 4 个 OSD、单副本 | block_bench | 约 81.6 万 | 约 353us |
| 4 个 OSD、三副本(同机) | block_bench | 约 35 万 | 约 446us |
同一报告中还有几条对判断路径损耗有用的对比:虚拟机路径(vhost + 虚机内 fio)在单副本下约 32.1 万 IOPS,与 block_bench 差距不大,损耗主要在虚机内部 IO 与 vhost 通信;NVMe-oF 导出在四 OSD 单副本下,RDMA 传输约 78.4 万,与 block_bench 接近,而 TCP 传输损耗明显更大。报告同时提示,三副本全部压在同一台服务器上受本机资源限制,若分布到三台服务器 IOPS 会显著提高——所以读结果时应先看拓扑,再对比数字,报告里也同步记录了网卡与磁盘的利用率截图作为佐证。
🚧 ## 需要留意的边界与演进方向
当前主线是 CMake + SPDK + 用户态客户端;仓库顶层另有一个 kfastblock 内核态块客户端,定位是研发验证版:已具备 attach、元数据拉取、对象级读写和最小块设备 smoke 闭环,但尚不适合生产级稳定性与性能验收,关注内核态接入路径的读者可以留意其 TASKS.md 中的后续计划。
尚未完成或仍在演进的能力(来自项目 README)包括:卷快照与快照组、卷 QoS、OSD 与客户端的多核性能优化、DPU 卸载 vhost、卷加解密与卷共享。已完成的部分则涵盖 CI 接入、Monitor 的 PG 分配插件化、Raft 成员变更与 PG 分配联调、监控数据导出与运行时数据展示等,完整的性能与故障恢复数据可参考 docs/ 目录下的测试报告。
【免费下载链接】fastblockA distributed block storage system that uses mature Raft protocol and is designed for all-flash scenarios项目地址: https://gitcode.com/openeuler/fastblock
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考