近期,我们推出高性能 SSD 云盘,满足用户对高性能的场景需求。SSD 云盘相比普通云盘,IOPS 提升了 13 倍,稳定性提升了 3 倍,平均时延降低了 10 倍。为了做到这些,我们从去年 10 月份开始对云盘的架构进行了重新设计,充分减少时延和提升 IO 能力;并通过复用部分架构和软件,提供性能更好、更稳定的普通云盘;同时逐步引入 Stack/Kernel Bypass 技术,打造下一代超高性能存储。新架构推出后,已服务了现网用户的 3400 多个云盘实例,总存储容量达 800 TB,集群每秒 IOPS 均值 31 万。
架构升级要点
通过对现阶段问题和需求的分析,我们整理了这次架构升级的具体要点:
1 、解决原有软件架构不能充分发挥硬件能力的局限
2 、支持 SSD 云盘,提供 QOS 保证,充分发挥后端 NVME 物理盘的 IOPS 和带宽性能,单个云盘 IOPS 可达 2.4W
3 、支持更大容量云盘,32T 甚至更大
4 、充分降低 IO 流量的热点问题
5 、支持并发创建几千块云盘,支持并发挂载几千块云盘
6 、支持老架构云盘在线向新架构迁移,支持普通云盘在线迁移至 SSD 云盘
新架构改造实践
改造一:IO 路径优化
老架构中,整个 IO 路径有三大层,第一层宿主 Client 侧,第二层 Proxy 侧,第三层存储 Chunk 层。Proxy 负责 IO 的路由获取以及缓存;IO 的读写转发到下一层存储层,负责 IO 写三份复制。
而新架构中,路由获取交给了 Client,IO 读写 Client 可直接访问存储 Chunk 层,写三份复制也交给了 Chunk。整个 IO 路径变成了 2 层,一层是宿主 Client 侧, 另一层存储 Chunk 层。
架构升级之后,对读 IO,一次网络请求直达到后端存储节点,老架构都是 2 次。对写 IO,主副本 IO 一次网络请求直达后端存储节点,另外 2 副本经过主副本,经历两次网络转发,而老架构三个副本均为两次。读 IO 时延平均降低 0.2-1ms,写尾部时延减低,也有效的降低总体时延。
改造二:元数据分片
分布式存储中,会将数据进行分片,从而将每个分片按多副本打散存储于集群中。如下图,一个 200G 的云盘,如果分片大小是 1G,则有 200 个分片。老架构中,分片大小是 1G,在实际业务过程中我们发现,部分业务的 IO 热点集中在较小范围内,如果采用 1G 分片,普通 SATA 磁盘性能会很差。并且在 SSD 云盘中,也不能均匀的将 IO 流量打散到各个存储节点上。
新架构中,我们支持了 1M 大小的分片。1M 分片,可以充分使用整个集群的能力。高性能存储中,因为固态硬盘性能较好,业务 IO 热点集中在较小范围内,也能获得较好的性能。
但 UCloud 元数据采用的是预分配和挂载方案,申请云盘时系统直接分配所有元数据并全部加载到内存。分片过小时,需要同时分配或挂载的元数据量会非常大,容易超时并导致部分请求失败。
例如,同时申请 100 块 300G 的云盘,如果按 1G 分片,需要同时分配 3W 条元数据;如果按照 1M 分片,则需要同时分配 3000W 条元数据。
为了解决分片变小导致的元数据分配/挂载失败问题,我们尝试改变 IO 时的分配策略,即云盘挂载时,将已分配的元数据加载到内存中。IO 时,如果 IO 范围命中已经分配路由,则按内存中的路由进行 IO;如果 IO 范围命中未分配路由,则实时向元数据模块请求分配路由,并将路由存储在内存中。
按 IO 时分配,如果同时申请 100 块 300G 的云盘, 同时挂载、同时触发 IO,大约会产生 1000 IOPS,偏随机。最坏情况会触发 1000 * 100 = 10W 元数据分配。在 IO 路径上,还是存在较大消耗。
最终,新架构中我们放弃了中心节点存储分片元数据的方案,采用了以一套统一规则去计算获取路由的方案。
该方案中,Client 端和集群后端采用同样的计算规则 R(分片大小、pg 个数、映射方法、冲突规则);云盘申请时,元数据节点利用计算规则四元组判断容量是否满足;云盘挂载时,从元数据节点获取计算规则四元组; IO 时,按计算规则 R(分片大小、pg 个数、映射方法、冲突规则)计算出路路由元数据然后直接进行 IO。通过这种改造方案,可以确保在 1M 数据分片的情况下,元数据的分配和挂载畅通无阻,并节省 IO 路径上的消耗。
改造三:支持 SSD 高性能云盘
通过上述对比可以看到,NVME 固态硬盘性能百倍于机械盘,但需要软件的配套设计,才能利用 NVME 固态硬盘的能力。
SSD 云盘提供 QoS 保证,单盘 IOPS:min{1200+30* 容量,24000} 对于 SSD 云盘,传统的单线程模式会是瓶颈,难以支持后端 NVME 硬盘几十万的 IOPS 以及 1-2GB 的带宽,所以我们采用了多线程模型。
为了较快推出 SSD 云盘,我们还是采用了传统 TCP 网络编程模型,未使用 Kernel Bypass。同时,通过一些软件细节的优化,来减少 CPU 消耗。
目前,单个线程写可达 6W IOPS,读可达 8W IOPS,5 个线程可以基本利用 NVME 固态硬盘的能力。目前我们能提供云盘 IO 能力如下:
改造四:防过载能力
对于普通云盘,新架构的软件不再是瓶颈,但一般的机械硬盘而言,队列并发大小只能支持到 32-128 左右。100 块云盘,持续同时各有几个 IO 命中一块物理 HDD 磁盘时,因为 HDD 硬盘队列并发布较小,会出现较多的 io_submit 耗时久或者失败等问题。Client 侧判断 IO 超时后,会重试 IO 发送,造成 Chunk 端 TCP 缓冲区积压越来越多的 IO 包,越来越多的超时积压在一起,最终导致系统过载。
对于普通云盘,需控制并发提交队列大小,按队列大小,依次遍历所有云盘,下发各云盘的 IO,如上图的 1、2、3。实际代码逻辑里,还需要考虑云盘大小的权重。
对于 SSD 云盘来说,传统的单个线程会是瓶颈,难以支持几十万的 IOPS 以及 1-2GB 的带宽。
压测中,我们模拟了热点集中在某个线程上的场景,发现该线程 CPU 基本处于 99%-100% 满载状态,而其它线程则处于空闲状态。后来,我们采用定期上报线程 CPU 以及磁盘负载状态的方式,当满足某线程持续繁忙而有线程持续空闲时,选取部分磁盘分片的 IO 切换至空闲线程,来规避部分线程过载。
改造五:在线迁移
老架构普通云盘性能较差,部分普通云盘用户业务发展较快,希望从普通云盘迁移至 SSD 云盘,满足更高的业务发展需要。目前线上存在 2 套老架构,为了快速达到在线迁移的目的,我们第一期决定从系统外围支持在线迁移。
迁移流程如下:
1 后端设置迁移标记;
2 Qemu 连接重置到 Trans Client;
3 写 IO 流经过 Trans Client 到 Trans 模块,Trans 模块进行双写:一份写老架构,一份写新架构;
4 Trigger 遍历磁盘, 按 1M 大小触发数据命令给 Trans 触发数据后台搬迁。未完成搬迁前,IO 读经 Trans 向旧架构 Proxy 读取;
5 当全部搬迁完成后,Qemu 连接重置到新架构 Client,完成在线迁移。
加一层 Trans 及双写,使迁移期间存在一些性能损耗。但对于普通云盘,迁移期间可以接受。我们目前对于新架构也正在建设基于 Journal 的在线迁移能力,目标在迁移期间,性能影响控制在 5% 以下。
经过上述系列改造,新的云硬盘架构基本完成了最初的升级目标。目前,新架构已经正式上线并成功运用于日常业务当中。在这里,也谈谈我们正在研发的几项工作。
1、容量具备无限扩展能力
每个可用区,会存在多个存储集群 Set. 每个 Set 可提供 1PB 左右的存储 (我们并没有让集群无限扩容)。当 Set1 的云盘需要从 1T 扩容至 32T 100T 时,可能会碰到 Set1 的容量不足的问题。
因此,我们计划将用户申请的逻辑盘,进行分 Part, 每个 Part 可以申请再不用的 Set 中,从而具备容量可以无限扩展的能力。
2、超高性能存储
近 10 年,硬盘经过 HDD -> SATA SSD -> NVME SSD 的发展。同时,网络接口也经历了 10G -> 25G -> 100G 的跨越式发展。然而 CPU 主频几乎没有较大发展,平均在 2-3GHZ,我们使用的一台物理机可以挂 6-8 块 NVME 盘,意味着一台物理机可以提供 300-500 万的 IOPS.
传统应用服务器软件模式下,基于 TCP 的 Epoll Loop, 网卡的收发包,IO 的读写要经过用户态、内核态多层拷贝和切换,并且需要靠内核的中断来唤醒,软件很难压榨出硬件的全部能力。例如在 IOPS 和时延上,只能靠叠加线程去增加 IOPS,然而,IOPS 很难随着线程的增加而线性增长,此外时延抖动也较高。
我们希望通过引入零拷贝、用户态、轮询的技术方案来优化上图中的三种 IO 路径,从而减少用户态、内核态、协议栈的多层拷贝和切换,并结合轮询一起压榨出硬件的全部能力。
最终,我们选择了 RDMA,VHOST,SPDK 三个技术方案。
方案一:超高性能存储-VHOST
传统模式如下,IO 经过虚机和 Qemu 驱动,再经过 Unix Domain Socket 到 Client。 经过多次用户态内核态,以及 IO 路径上的拷贝。
而利用 VHOST User 模式,可以利用共享内存进行用户态的 VM 到 Client 侧的数据传输。在实际中,我们利用了 SPDK VHOST。
研发环境中,我们将 Client 收到 IO 请求后立即模拟返回给 VM,也就是不向存储后端发送数据,得到的数据如上图。单队列时延可以降低 90us,IOPS 有几十倍的提升。
方案二:超高性能存储-RDMA+SPDK
RDMA 提供了一种消息服务,应用程序利用 RDMA 可以直接访问远程计算机上的虚拟内存,RDMA 减少了 CPU 占用以及内存带宽瓶颈,提供了很高的带宽,并利用 Stack Bypass 和零拷贝技术,提供了低延迟的特性。
SPDK 可以在用户态高并发零拷贝地以用户态驱动直接访问 NVME 固态硬盘。并利用轮询模式避免了内核上下文切换和中断处理带来的开销。
目前团队正在研发利用 RDMA 和 SPDK 的存储引擎框架,研发测试环境中,后端用一块 NVME 固态盘,我们在单队列和 IOPS 上可以提升如下:
包括 SPDK VHOST USER 的 Client 侧,以及 RDMA+SPDK 的存储侧方案,预计 12 月会推出公测版。
总结
过去的一年时间里,我们重新设计和优化了云盘的存储架构,解决了过去老架构的诸多问题,并大幅提升了性能。经过 4 个月公测,SSD 云盘和新架构普通云盘都于 8 月份全量上线,并保持了极高的稳定性,目前单盘可提供 2.4W IOPS。
同时,为了追求更佳的 IO 体验,我们引入 Kernel/Stack Bypass 技术方案,正在打造更高性能、更低时延的存储引擎,预计 12 月份会推出超高性能云盘公测版,敬请期待!