简介
2024 年 3 月 2 日至 3 月 6 日,在英国爱丁堡举行了第30届IEEE高性能计算机体系结构国际研讨会HPCA(30th IEEE International Symposium on High-Performance Computer Architecture),HPCA是计算机体系结构领域的四大顶级会议之一。由阿里云服务器研发团队和蚂蚁数据基础设施与高可用团队合作完成的论文《LightPool: A NVMe-oF-based High-performance and Lightweight Storage Pool Architecture for Cloud-Native Distributed Database 》入选。
新兴的云原生分布式数据库依靠本地NVMe SSD为众多云应用提供高性能、高可用的数据服务。然而,由于各节点内CPU和存储容量不平衡,数据库集群的本地存储利用率较低。例如,OceanBase分布式数据库集群,拥有数百PB的本地存储容量,但本地存储利用率仅为40%左右。虽然分解存储(EBS)可以通过按需独立配置CPU和存储来提高存储利用率,但它们存在性能瓶颈和高昂的成本。
在本文中,作者提出了LightPool,一种高性能、轻量级的存储池架构,大规模部署在OceanBase集群中,提高存储资源利用率。 LightPool的核心思想是将集群存储聚合到存储池中并实现统一管理。
1 背景
**1.1NVMe(Non-Volatile Memory Express) && NVMe over Fabrics (NVMe-oF) **
NVMe (Non-Volatile Memory Express):一个专门为固态硬盘设计的高速传输协议。NVMe通过PCIe总线连接,支持多队列并行处理,能够大幅提升带宽和减少延迟,相较传统硬盘和SATA-SSD具有显著的性能优势。因此NVMe SSDs成为了云数据中心满足高I/O密集型应用需求的首选
NVMeover Fabrics (NVMe-oF):这是NVMe的扩展协议,用于通过网络(称为“fabric”)访问远程的NVMe设备,在远程访问场景中提供接近本地存储的高性能。NVMe-oF支持不同的网络协议(如RDMA和TCP),在云数据中心中,通常选择TCP协议因其稳定性和无需硬件支持的特点,而RDMA则适合于特殊的高性能环境

1.2 Kubernetes
Kubernetes 是一个流行的容器编排系统,广泛应用于云数据中心。其主要架构包括控制平面节点和工作节点。在 Kubernetes 集群中,Pod 是最小的工作负载单元,每个 Pod 包含一个或多个运行的容器。Kubernetes 提供了一种灵活的方式来管理和分配计算资源,从而使应用程序能够根据需求自动扩展和调度。

1.3 容器存储(Container Storage)
容器存储(Container Storage)在 Kubernetes 集群中,存储提供者为 Pod 提供持久化存储,以“卷”的形式存在。常见的存储选项包括本地存储、分离式存储方案、共享存储方案。
- 本地存储方案允许用户直接访问与同一工作节点相连的存储设备,从而实现高吞吐和低延迟。
- 分离式存储方案通过网络访问远程的专用存储集群。OpenEBS 提供高可靠的存储,支持多数据副本,并通过 NVMe-oF 将数据副本存储到其他节点。
- 共享存储方案是上述两种方案的结合。

2 动机
现有方案的问题
- **计算存储结合:**这种本地存储服务以其高性能、低成本的优势而受到青睐。然而,它可能导致资源调度问题和资源利用率的不均衡,即服务器与业务需求的不匹配可能会造成资源的碎片化,降低了单个服务器资源的使用效率。
- **计算存储分离(ECS + EBS/S3):**计算存储分离架构利用分布式云存储的能力解决资源碎片问题。尽管如此,分布式存储服务可能会带来较大的爆炸半径、增加成本(存储层额外的数据副本)和增加延迟(较长的I/O链路)。这一架构适用于中小规模业务,但对于那些对集群规模、I/O性能、吞吐量和成本敏感的大型业务来说,可能并不合适。
- **共享存储架构(例如PolarStore、Aurora、Oracle RAC):**共享存储架构能够有效解决上述问题,通过与存储产品内核深度集成的共享分布式存储,它能够在降低成本和减少副本的同时提供满意的性能。但是,这种方案的通用性较差,每个存储产品都需要深度定制和优化。
在云原生分布式数据库中,不需要存储系统来保证数据可靠性,因为它们在数据库级别支持多个数据副本(如下图所示,P0-P3的多个数据复制副本)。云原生分布式数据库不需要在存储系统层面维护多个数据副本,这促使我们设计一种轻量级、高通用性的存储池架构,专注于接近本地存储的高性能,且无需数据副本。

3 设计与实现
3.1 LightPool集群架构
LightPool集群角色分为控制节点和工作节点:
-
**控制节点:**负责集群所有SSD的池化管理,SSD资源的分配和回收的管控,控制节点融入了k8s管控框架,通过资源调度器的方式和k8s的master服务进行交互,和k8s master节点部署在一起,控制节点只会在容器申请/释放存储资源的时候介入,而在IO的正常读写阶段,控制节点被bypass,IO的读写只会在工作节点之间交互。
-
**工作节点:**运行了业务的容器,同时部署了LightPool的存储引擎以及CSI插件,存储引擎负责接管工作节点上的所有本地存储资源,CSI插件等负责容器申请到的存储资源的挂载。在控制节点完成容器存储资源的分配后,容器所在的工作节点和存储资源所在的工作节点之间通过NVMe over Fabric高性能存储协议互联,实现了本地存储的弹性。
下图集群中包含了不同的ECS服务器,其中存储型的ECS(如Node 1)搭载了大量的本地SSD,而计算型的ECS如(Node 2 和Node 3)搭载了少量甚至不搭载本地SSD。这种服务器的配置在现实中较为常见,源于上层不同的业务因为不同的负载对服务器的需求不同,但是随着服务器数量和业务的变更,后续又往往会考虑不同的业务进行服务器资源的共享池来提升资源的使用效率。在这种情况下当业务通过容器在整个资源池进行动态调度和部署的时候,需要同时考虑CPU,内存,磁盘三个维度的资源,而数据库业务对存储的大容量需求进一步导致了调度的复杂度,使得资源池的资源利用率无法达到较高的水平。LightPool架构目的就是这种情况下解耦了调度对磁盘的耦合性,使得容器调度主要聚集考虑CPU和内存,磁盘可以通过弹性的方式进行挂载,从而解决资源利用的问题。

3.2 LightPool核心组件
架构分为以下两个核心组件和节点类型:
节点类型:
- 控制平面节点:在Kubernetes控制平面节点上运行LightPool-Controller,用于管理集群中所有的存储资源,并在收到请求时为工作节点分配合适的存储资源。
- 工作节点:这些节点用于运行应用容器,并根据配置运行LightPool组件。一些工作节点配备NVMe SSD,用于直接提供存储服务,而另一些节点则仅用于运行应用而没有附加的存储设备。每个工作节点可以通过LightPool-Controller访问自身或其他工作节点上的存储资源。
核心组件:
- LightPool-Controller:这是LightPool架构的核心,驻留在Kubernetes控制平面节点上,负责全局存储资源视图的维护和集群内存储卷的分配。该控制器包含两个子组件:
- 存储调度器:在检测到存储请求时,选择在集群中有足够空间的目标节点
- 卷管理器:用于实际的卷分配与管理。
- LightPool-Initiator和LightPool-Engine:部署在工作节点上,提供高性能的I/O路径来访问本地和远程存储,并通过轻量级的I/O栈和零拷贝机制提升本地存储的访问效率

3.3 分配策略
当新应用 pod 创建时,Kubernetes 控制平面节点上的 LightPool-Controller 接收存储需求并选择一个工作节点作为目标。然后,选定工作节点上的 LightPool-Agent 分配指定容量的存储卷,并通知 LightPool-Engine 等待连接。
LightPool-Controller 中的存储调度器采用两阶段分配策略。首先,在预筛选阶段,调度器遍历节点列表,识别符合存储需求的工作节点。接着,在选择阶段,调度器根据节点是否满足用户的本地/远程偏好及剩余可用容量比例对工作节点进行评分,最终选择得分最高的节点作为目标。
此策略优先从空闲存储容量较少的节点分配存储资源,以减少碎片化,并为未来的大容量存储请求保留足够空间。确定存储提供者后,选定工作节点上的 LightPool-Agent 通知 LightPool-Engine 创建指定容量的逻辑卷。然后,应用工作节点上的 LightPool-Initiator 通过 Kubernetes 组件(CSI Driver)连接到选定工作节点上的 LightPool-Engine,最后,应用 pod 可以使用该节点上的存储资源。

3.4 I/O路径-remote
远程 I/O 路径:在 LightPool 中,远程 I/O 路径如图 5a 所示。LightPool-Initiator 在内核中以标准 NVMe 块设备的形式暴露给应用 pod,应用 pod 通过挂载在标准 NVMe 设备上的文件系统进行读写,而不需了解物理磁盘的位置。
- 应用 pod 发起 I/O 请求。
- 应用工作节点上的 LightPool-Initiator 接收请求。
- 通过 TCP 堆栈(网络接口卡)将请求转发至目标工作节点的用户级 LightPool-Engine。
- LightPool-Engine 将请求转换为 NVMe 命令,并通知物理存储设备执行。
- 存储设备接收命令并在 LightPool-Engine 的数据缓冲区中读写数据。
- 数据通过 TCP 从 LightPool-Engine 发送回 LightPool-Initiator。
- 最后,数据被复制到应用缓冲区中。

3.5 I/O路径-local
本地 I/O 路径:下图展示了应用 pod 在同一工作节点上访问存储资源的本地 I/O 路径。为提高性能,通过 IOMMU 页表设置实现 DMA 重映射的方式,将用户缓冲区地址替换为 IOVA。
- 应用 pod 发起 I/O 请求。
- 应用工作节点上的 LightPool-Initiator 接收请求。
- LightPool 引入了一种零拷贝传输机制。对于 I/O 请求传输,LightPool-Initiator 和 LightPool-Engine 使用共享内存,LightPool-Initiator 将请求转换为 NVMe 命令,并用 IOVA 替换用户缓冲区地址。
- LightPool-Engine 接收 NVMe 命令,将其加入提交队列并通知物理存储设备执行命令。
- 对于数据传输,通过 DMA 重映射使本地存储设备可直接访问应用缓冲区。此零拷贝传输通过共享内存消除了冗余拷贝,实现了接近本地存储的原生性能。
共享内存允许 Initiator 和 Engine 直接访问同一块内存区域,因此无需将数据从一个内存区域复制到另一个区域。这避免了通常在用户态和内核态之间进行的两次数据拷贝,
传统策略中本地磁盘的 I/O 请求和数据通过 TCP 回环在 LightPool-Initiator 和 LightPool-Engine 之间传输,导致两个冗余的数据拷贝,造成性能下降和 CPU 负担

3.6 高可用性设计
存储服务可用性与存储性能同样重要。为了向容器提供高可用存储服务,LightPool设计了热升级(Hot-upgrade)和热迁移(Hot-migration)机制,可以分别升级LightPool引擎和将容器数据迁移到其他节点,而无需应用程序感知。
热升级(Hot-upgrade) :
LightPool-Engine 是 LightPool I/O 路径中的关键组件,需要定期升级以添加新功能和修复漏洞。为了确保升级过程不中断应用 I/O,LightPool设计了热升级机制。
在热升级开始时,LightPool-Engine 进入热升级状态并调用 fork 系统调用创建新版本的子进程。子进程等待父进程(旧版本)完成现有任务。父进程停止接收新的 I/O 请求,等待当前请求完成后关闭所有子系统并退出。此期间应用发送的 I/O 请求会被阻塞,但不会报错。
当子进程检测到父进程退出后,开始根据配置文件恢复子系统并重新与 Initiator 建立 TCP 连接。最后,子进程(新版本的 LightPool-Engine)开始处理 I/O 请求,完成热升级过程。
热迁移(Hot-migration):
在生产集群中,为了维护或释放存储容量,管理员需要将应用数据迁移到其他节点。为此,提出了一种基于多路径 I/O 动态切换的热迁移机制,保证迁移过程不中断存储服务。
步骤:
A:初始化:在新节点创建与旧节点相同的子系统,LightPool-Initiator 连接到新子系统,但保持非活跃状态。
B:数据复制:旧节点开始多轮数据复制,记录数据修改并逐轮更新。最后一轮数据复制时暂停应用请求并完成复制。
C:路径切换:完成复制后,LightPool-Initiator 切换 I/O 路径到新节点,断开旧连接并启用新连接,避免服务中断。
此机制保障了热迁移过程中用户数据读写的连续性。

3 实验评估
4.1 实验环境
表I显示了LightPool的详细实验设置。构建了一个4节点的Kubernetes集群,包括一个控制平面节点和三个工作节点。实验采用了 centos: 7 Docker 映像并安装了评估应用程序来评估存储 I/O 性能。还禁用了超线程和节能状态,以便在服务器上进行准确的性能测量。生产数据来自 OceanBase 生产集群的监测系统。

4.2 IOPS 和带宽性能
下图展示了原生磁盘、LightPool、未优化的 LightPool(LP-NoOpt)和 OpenEBS 的 IOPS 和带宽性能。LightPool 的性能达到了原生磁盘的 93.2%-103.4%,表明其性能损耗和开销极小。而 OpenEBS 在随机读写测试中仅达到原生磁盘的 34.0% 和 46.3%。在最佳情况下,LightPool 的性能比 OpenEBS 高 190.9%。
LightPool 由于轻量级的软件堆栈,实现了接近原生的存储性能,而 OpenEBS 存在严重的性能下降。零拷贝机制使 LightPool 的带宽性能提升达 35.9%,有效优化了本地存储访问性能。


4.3 延迟表现
延迟性能:下图显示,LightPool 的平均延迟明显优于 OpenEBS,接近原生 NVMe SSD 的性能,这表明轻量化堆栈和零拷贝机制可以实现接近原生的低延迟。LightPool 在顺序和随机读写测试中仅比原生磁盘增加约 2.1 至 3.5 微秒的延迟。零拷贝机制消除了冗余数据拷贝,绕过了 TCP 回环,使应用 pod 访问本地存储时的平均延迟最多降低了 60.4%(在顺序写入测试中)。因此,LightPool 能以最小的开销提供高性能存储服务。

本地与远程性能:同时,评估了 LightPool 分配的本地和远程存储资源的平均延迟性能。对于远程存储资源,通过 2*25 Gbps 网络连接,远程存储相较于本地仅增加 55.2 至 67.3 微秒的固定延迟,但 I/O 吞吐量会受网络带宽影响。

4.4 可用性和热迁移
在测试热升级和热迁移期间,LightPool维持了高I/O吞吐量和低延迟。实验表明,热升级仅导致不到1秒的暂停时间,而热迁移过程保持了不间断的写操作,表明其高可用性。
为测量热升级引起的 I/O 暂停时间,测试了 4K 随机读写(队列深度为 1,1 个 FIO 任务)。结果显示,LightPool-Engine 的热升级仅需 1 秒即可完成(图 13)。在生产集群中进行了三次热升级测试,图 14 显示在热升级过程中,OceanBase 的 SQL 吞吐量最多下降 31.0%,延迟最多增加 1.49 倍,持续时间不到 10 秒,可被 OceanBase 实例接受。


在热迁移测试中,分配了一个 400GB 的卷,使用 4KB 块大小的 FIO 持续写入数据,随后启动热迁移。热迁移在 7 轮内完成,每轮的数据迁移带宽如图 15 所示。整个热迁移过程中, 写 I/O 没有中断。

4.5 生产环境部署测试
在生产环境中,LightPool已部署在超过8500个节点上,支持OceanBase的高性能存储需求,集群的存储资源利用率从约40%提升至65%。在实际工作负载中,LightPool的整体吞吐率达到了原生磁盘的99.2%,与OpenEBS相比提高了6.9%

5 总结
这篇论文介绍了LightPool,一个基于NVMe-oF的高性能、轻量级存储池架构,专为云原生分布式数据库(如OceanBase)设计。LightPool旨在解决现有分布式数据库在存储资源利用、性能和成本上的挑战,尤其是本地存储利用率低、分离式存储的带宽瓶颈和高成本问题。
解决的问题:
- 云原生数据库需要高性能和低延迟的存储系统,以满足数据密集型应用的需求。
- 本地NVMe存储虽然性能优异,但通常在集群内资源利用率低下,导致总拥有成本(TCO)增加。
- 分离式存储解决方案存在性能瓶颈和高成本问题,无法有效支持云原生分布式数据库的高并发需求。
核心设计:
- LightPool通过将集群的存储资源整合为共享存储池来提升资源利用率。
- 采用NVMe-oF协议,实现跨节点的高性能存储共享,并在Kubernetes中进行资源动态分配和管理。
- LightPool采用轻量化I/O栈和零拷贝机制,以接近本地存储的性能提供服务,并设计了热升级和热迁移机制,以确保高可用性。