NVMe SPDK

长期以来,SATA、SAS盘统治着企业级存储,虽然前些年 SSD固态存储介质的出现对 AHCI协议类型的存储访问带来了一定性能提升,但与 CPU 的计算速度相比,只能是杯水车薪,并且 SSD 的性能也不能充分地得到发挥。传统存储技术也由于访问路径长、时延大和吞吐量低而越发不能满足 “大数据” 存储的需求,并且饱受诟病。

近几年推出的 NVMe 技术以 PCIe作为 SSD 的访问接口,极大地缩短了 I/O 的访问路径,同时 NVMe 的软件栈也以精简的调用关系进一步降低了数据访问的时延。可以说,NVMe 技术的出现和快速发展,是对存储技术领域的重大革新。由此 NVMe 存储的应用自然成了业内的发展趋势,各厂商也都积极投入NVMe存储的研发中来。

越来越多的分布式文件系统积极参与全闪阵营,通过横向扩展能力,对外提供块、对象、文件服务接口及一些增值特性服务,可以通过存储节点堆叠,获得容量和性能的同步提升。硬件上使用 RDMA、NVMe、NVDIMM等先进技术,提供高性能的硬件节点;同时采用软硬件一体化的设计达成高可靠性的目标。为了减少存储产品面临的传统共性问题,如频繁的系统调用和上下文切换、多次的数据拷贝、过高的协议栈开销、复杂的并发互斥等痛点问题,在用户态化实现的过程中,引入了 Intel 的 DPDK/SPDK作为关键基础技术来进行集成和开发。基于 DPDK 和 SPDK 的用户态实现前端NVMe-oF、FCP、iSCSI 块服务相关接口。

DPDK/SPDK 技术的引入,通过大页(Huge page)、轮询、分核、无锁化等机制减少了 CPU 上下文切换、并发互斥等带来的系统开销,提高了 I/O 的响应速度,带来了系统性能的提升,有效地解决了前端网络、后端网络和落盘等环节存在的性能瓶颈。同时 SPDK 提供的 BDEV 框架,定义了上层的访问接口,和下层存储设备的注册接口,向上可以支撑多种不同协议的Target,向下可以挂载多种不同的存储设备。BDEV 框架实现了对后端存储设备的统一抽象,可以和后端存储解耦,产品前后端可针对框架开发,减小模块耦合,进行独立的测试验证,提高了产品开发维护的效率。

Intel DPDK/SPDK 技术作为该产品设计的关键一环,与分布式架构融合应用,充分发挥全闪(NVMe)存储设备和 RDMA 传输通道的能力,提供了高性能的系统特性。当前产品开发的先期任务主要完成针对新技术的可行性分析、验证及高性能硬件节点的原型机开发:兼容业界主流厂商的 RDMA、FC卡,并基于 DPDK/SPDK 实现前端 NVMe-oF、FCP、iSCSI 块服务类型接口。当前的开发实现,验证了新一代全闪(NVMe)技术的高性能能力,为最终的分布式全闪(NVMe)存储产品的实现打下了坚实的基础。

SPDK NVMe-oF 介绍

SPDK是 Intel 提供的高性能存储开发套件,在 DPDK 基础上实现(封装了 DPDK 的一些资源管理的组件,例如 CPU,内存和PCI 设备管理等)。其核心是基于用户态、异步、轮询方式实现的一套编程框架(SPDK Application Framework),以及在该框架下开发的 NVMe 驱动和 Target。同时,SPDK 也提供了一个用户态的块设备抽象层(Block Device Abstract Layer)用以支持开发人员按需构造私有的、高效的存储应用。SPDK 主要架构可如下图。

NVMe SPDK

SPDK 的应用框架可概述为:

其一,对 CPU core 和线程的管理;

其二,线程间的高效通信;

其三,I/O 的处理模型以及数据路径(data path)的无锁化机制。

这几个机制的共同配合,使得SPDK形成了一套低 I/O 时延和单 CPU 核 IOPS最大化的高性能解决方案。块设备抽象层通过 BDEV 框架向前与存储协议层对接,支持各类 Target 的实现;向后通过对块设备的抽象可以适配各类型的存储设备。并且用户可以基于 BDEV 框架开发自己特有的应用策略,实现差异化的应用场景。SPDK 同时实现了后端 NVMe 盘的用户态驱动和在前端支持主机远程访问 NVMe 块设备的 Target,在 NVMe 的使用场景具有天然的优势。可以毫不夸张地说,SPDK 支持的核心业务主要就是 NVMe Over Fabrics,即 NVMe-oF。基于 SPDK 的 NVMe-oF 应用层次关系如下图。

NVMe SPDK

NVMe-oF 的核心思想在于让 I/O 的各个阶段均在同一个 CPU 核上处理,以此来实现免锁和性能最大化。其关键实现主要是 nvmf功能模块。nvmf 功能模块一方面通过 Transport层的实现机制屏蔽了底层 “通道”(当前主要是 RDMA、FC、 TCP)实现的差异;同时也藉由 BDEV 层的抽象,可以对接各类型的块设备。基于 SPDK 的应用编程框架机制,NVMe-oF 可以实现将各个 I/O 的所有操作在同一个 CPU 核上完成处理,有效减少了上下文切换和并发访问带来的开销,并且能让 I/O 均匀地分布在各个 CPU 核上,进一步提升了系统的性能。

SPDK 实现上采用了模块化的设计思路。简单而言,可以将SPDK 套件的内容分为三个层次:

其一,基础环境层,主要是调用 DPDK 接口进行底层运行环境的初始化,同时构建 SPDK 基于 CPU 核进行串行、轮询的调度机制;

其二,诸如 bdev、nvmf、nvme等分别归集的核心功能模块,实现具体的业务逻辑功能;

其三,特定应用示例的实例程序和测试框架代码,集成和运行各个功能组件。这样的设计和实现策略使得 SPDK 具有很强的适应性和可扩展性,用户可以根据需要灵活地进行修改或二次开发,来实现特定场景的应用。

SPDK NVMe-oF 应用方案介绍

H3C当前产品的先期开发,主要是完成了通过 SPDK 对接主流厂商的 RDMA 卡以及FC卡来实现块存储服务类型的 NVMe-oF、FCP、iSCSI 的接口,以支持相应 Target 运行业务。目前使用 Intel DPDK/SPDK 的具体方案框架如下图所示。方案支持业界主流厂商的 RDMA 卡驱动运行在内核态,通过 Verbs框架的接口向上支撑 SPDK 的调用,向下屏蔽不同卡的底层实现差异,同时 FC 卡的驱动直接使用 DPDK 的机制在用户态实现,提供接口支撑上层使用。

NVMe SPDK

对于 NVMe-oF 而言,在 SPDK 的 nvmf 功能模块中,通过 Transport 层屏蔽了作为 “传输通道” 的 FC 和 RDMA 的实现差异,具体如图所示。

NVMe SPDK

在基于 SPDK 进行二次开发的过程中,主要完成了如下方面的修改或实现,具体可参见表所述。

1. 增加了 FC Transport 的具体实现;产品需要在前端同时通过 RDMA 及 FC 通道支持 NVMe-oF 业务,因而针对需要的使用场景,增加了nvmf Transport 层的 FC 实现。

2. 增加了 FC 卡的用户态驱动;该驱动基于 DPDK 及 UIO驱动框架实现,主要包含硬件适配、通用管理、连接处理,I/O 处理等功能。

3. 调整了接口分层;为了更符合实际业务场景的使用需求,增加操作、管理的灵活性,也为了减少模块对外的耦合,在考虑后续版本升级和兼容的情况下,对 SPDK nvmf 功能模块的代码作了如下分层封装。

4. 增加了NQN 的唯一性机制;在 NVMe-oF 应用中,需要确保 subsystem的 NQN 的唯一性,至少在当前网络域内是唯一的,因此引入了 NQN 与节点唯一标识相结合的方案。这样,只要能保证节点内的 subsystem 的 NQN 不重复,即可保证网络内 NQN 不重复。

NVMe SPDK

5. 增加abort 的处理;集成的 SPDK 版本尚未支持对 abort 命令的响应,在 nvmf 功能模块来模拟实现对 abort 命令的支持。

6. 断链时等待 I/O 归零;断链过程(可能是主动断链或者异常出现时的断链)中,可能有 I/O 请求还在处理,此时若直接释放链接资源,则有可能会存在未处理完成的请求访问非法资源的情况。因而断链过程中需要等待 I/O 请求的完成。

7. 主动断链;增加 Target 侧主动断开链接功能的支持,特别是针对跑业务过程中出现重大错误时的处理。

8. Target 侧 keep-alive 机制;NVMe Over Fabrics Spec 中定义了由主机定期发送 keepalive 报文来判断通道是否正常的机制,当网络不通畅时,主机可以感知,并主动断开链接。但如果网络突然完全中断后,主机断开链接的请求无法到达 Target 侧,并且 Target 也无法感知网络的中断,之前与相关主机的链接会持续存在,一方面造成资源泄漏,另外也可能对网络恢复后的业务恢复产生影响(如 Target 侧会认为已与当前新来的主机建立了链接拒绝重复建链等)。

9. 性能统计;为了更好地统计每个 I/O 请求从到达 Target 侧后一直到响应从 Target 侧返回的这个过程中各个阶段的时延情况,当前开发过程中对 I/O 请求进行了阶段标识并进行打点计时统计,可以清晰看到实时的时延变化及 IOPS 情况的统计,增加了可定位性手段。

10. 监听的合法性判断及同主机同 port 拒绝重复建链;集成的 SPDK NVMe-oF 应用中,暂未实现 “认证”、“加密” 等相应内容,目前能做合法性判断策略的主要就是监听和检查主机的合法性。当前的实现中,一方面,增加了对请求所属的监听是否当前 subsystem 所允许的合法性判断,同时也对同一个主机,通过同一个 port(主机侧的 port 和 Target 侧的监听均一样)来进行重复建链(建立控制链接)的情况的限制。

11. cli 功能添加;为了便于调试及问题定位,在开发过程中增加了独立的 cli 功能,可以支持命令的动态查询、创建、设置等操作,提高了系统的可定位性和可维护性。

12. 可靠性问题修改;在本项目的开发过程中,修改了许多可靠性问题,如异常处理不完善、Target 进程主动终止时异常退出等,总体的解决思路均是:遵从 SPDK 分核思路,将操作通过 SPDK 的分核轮询机制串化、延后处理,实现免锁和消除并发。如下可列举部分已解决的典型问题。

  • 1) 共享断链时 RDMA 的共享完成队列报错及造成非法地址访问的问题;
  • 2) 断链时判断当前链接数并发造成的判断不准;
  • 3) 创建监听时的异常处理;
  • 4) 主动终止进程时出现的异常退出。

总体而言,本项目对 SPDK 的nvmf、iSCSI等模块做了相应的扩展和修改,以更符合实际的业务场景的需求。