热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SPDK技术运用对RSSD云硬盘的优化路径

下文给大家带来SPDK技术运用对RSSD云硬盘的优化路径,希望能够给大家在实际运用中带来一定的帮助,云硬盘涉及的东西比较多,理论也不多,网上有很

下文给大家带来SPDK技术运用对RSSD云硬盘的优化路径,希望能够给大家在实际运用中带来一定的帮助,云硬盘涉及的东西比较多,理论也不多,网上有很多书籍,今天我们就用编程笔记在行业内累计的经验做一个解答。

一 简介

用户对超高并发、超大规模计算等需求推动了存储硬件技术的不断发展,存储集群的性能越来越好,延时也越来越低,对整体IO路径的性能要求也越来越高。在云硬盘场景中,IO请求从生成到后端的存储集群再到返回之间的IO路径比较复杂,虚拟化IO路径尤其可能成为性能瓶颈,因为虚机内所有的IO都需要通过它下发给后端的存储系统。我们使用了SPDK来优化虚拟化IO路径,提出了开源未解决的SDPK热升级和在线迁移方案,并且在高性能云盘场景中成功应用,取得了不错的效果,RSSD云硬盘最高可达120万IOPS。本文主要分享我们在这方面的一些经验。

SPDK技术运用对RSSD云硬盘的优化路径

二 SPDK vhost的基本原理

SPDK(Storage Performance Development Kit )提供了一组用于编写高性能、可伸缩、用户态存储应用程序的工具和库,基本组成分为用户态、轮询、异步、无锁 NVMe 驱动,提供了从用户空间应用程序直接访问SSD的零拷贝、高度并行的访问。

在虚拟化IO路径中,virtio是比较常用的一种半虚拟化解决方案,而virtio底层是通过vring来通信,下面先介绍下virtio vring的基本原理,每个virtio vring 主要包含了以下几个部分:

desc table数组,该数组的大小等于设备的队列深度,一般为128。数组中每一个元素表示一个IO请求,元素中会包含指针指向保存IO数据的内存地址、IO的长度等基本信息。一般一个IO请求对应一个desc数组元素,当然也有IO涉及到多个内存页的,那么就需要多个desc连成链表来使用,未使用的desc元素会通过自身的next指针连接到free_head中,形成一个链表,以供后续使用。

available数组,该数组是一个循环数组,每一项表示一个desc数组的索引,当处理IO请求时,从该数组里拿到一个索引就可以到desc数组里面找到对应的IO请求了。

used 数组,该数组与avail类似,只不过用来表示完成的IO请求。当一个IO请求处理完成时,该请求的desc数组索引就会保存在该数组中,而前端virtio驱动得到通知后就会扫描该数据判断是否有请求完成,如果完成就会回收该请求对应的desc数组项以便下个IO请求使用。

SPDK vhost的原理比较简单,初始化时先由qemu的vhost驱动将以上virtio vring数组的信息发送给SPDK,然后SPDK通过不停的轮寻available数组来判断是否有IO请求,有请求就处理,处理完后将索引添加到used数组中,并通过相应的eventfd通知virtio前端。

当SPDK收到一个IO请求时,只是指向该请求的指针,在处理时需要能直接访问这部分内存,而指针指向的地址是qemu地址空间的,显然不能直接使用,因此这里需要做一些转化。

在使用SPDK时虚机要使用大页内存,虚机在初始化时会将大页内存的信息发送给SPDK,SPDK会解析该信息并通过mmap映射同样的大页内存到自己的地址空间,这样就实现了内存的共享,所以当SPDK拿到qemu地址空间的指针时,通过计算偏移就可以很方便的将该指针转换到SPDK的地址空间。

由上述原理我们可以知道SPDK vhost通过共享大页内存的方式使得IO请求可以在两者之间快速传递这个过程中不需要做内存拷贝,完全是指针的传递,因此极大提升了IO路径的性能。

我们对比了原先使用的qemu云盘驱动的延时和使用了SPDK vhost之后的延时,为了单纯对比虚拟化IO路径的性能,我们采用了收到IO后直接返回的方式:

1.单队列(1 iodepth, 1 numjob)

qemu 网盘驱动延时:

SPDK技术运用对RSSD云硬盘的优化路径

SPDK vhost延时:

SPDK技术运用对RSSD云硬盘的优化路径

可见在单队列情况下延时下降的非常明显,平均延时由原来的130us下降到了7.3us。

2.多队列(128 iodepth,1 numjob)

qemu 网盘驱动延时:

SPDK技术运用对RSSD云硬盘的优化路径

SPDK vhost延时:

SPDK技术运用对RSSD云硬盘的优化路径

多队列时IO延时一般会比单队列更大些,可见在多队列场景下平均延时也由3341us下降为1090us,下降为原来的三分之一。

三 SPDK热升级

在我们刚开始使用SPDK时,发现SPDK缺少一重要功能——热升级。我们使用SPDK 并基于SPDK开发自定义的bdev设备肯定会涉及到版本升级,并且也不能100%保证SPDK进程不会crash掉,因此一旦后端SPDK重启或者crash,前端qemu里IO就会卡住,即使SPDK重启后也无法恢复。

我们仔细研究了SPDK的初始化过程发现,在SPDK vhost启动初期,qemu会下发一些配置信息,而SPDK重启后这些配置信息都丢失了,那么这是否意味着只要SPDK重启后重新下发这些配置信息就能使SPDK正常工作呢?我们尝试在qemu中添加了自动重连的机制,并且一旦自动重连完成,就会按照初始化的顺序再次下发这些配置信息。开发完成后,初步测试发现确实能够自动恢复,但随着更严格的压测发现只有在SPDK正常退出时才能恢复,而SPDK crash退出后IO还是会卡住无法恢复。从现象上看应该是部分IO没有被处理,所以qemu端虚机一直在等待这些IO返回导致的。

通过深入研究virtio vring的机制我们发现在SPDK正常退出时,会保证所有的IO都已经处理完成并返回了才退出,也就是所在的virtio vring中是干净的。而在意外crash时是不能做这个保证的,意外crash时virtio vring中还有部分IO是没有被处理的,所以在SPDK恢复后需要扫描virtio vring将未处理的请求下发下去。这个问题的复杂之处在于,virtio vring中的请求是按顺序下发处理的,但实际完成的时候并不是按照下发的顺序的。

假设在virtio vring的available ring中有6个IO,索引号为1,2,3,4,5,6,SPDK按顺序的依次得到这个几个IO,并同时下发给设备处理,但实际可能请求1和4已经完成,并返回了成功了,如下图所示,而2,3,5,6都还没有完成。这个时候如果crash,重启后需要将2,3,5,6这个四个IO重新下发处理,而1和4是不能再次处理的,因为已经处理完成返回了,对应的内存也可能已经被释放。也就是说我们无法通过简单的扫描available ring来判断哪些IO需要重新下发,我们需要有一块内存来记录virtio vring中各个请求的状态,当重启后能够按照该内存中记录的状态来决定哪些IO是需要重新下发处理的,而且这块内存不能因SPDK重启而丢失,那么显然使用qemu进程的内存是最合适的。所以我们在qemu中针对每个virtio vring申请一块共享内存,在初始化时发送给SPDK,SPDK在处理IO时会在该内存中记录每个virtio vring请求的状态,并在意外crash恢复后能利用该信息找出需要重新下发的请求。

SPDK技术运用对RSSD云硬盘的优化路径

四 SPDK在线迁移

SPDK vhost所提供的虚拟化IO路径性能非常好,那么我们有没有可能使用该IO路径来代替原有的虚拟化IO路径呢?我们做了一些调研,SPDK在部分功能上并没有现有的qemu IO路径完善,其中尤为重要的是在线迁移功能,该功能的缺失是我们使用SPDK vhost代替原有IO路径的最大障碍。

SPDK在设计时更多是为网络存储准备的,所以支持设备状态的迁移,但并不支持设备上数据的在线迁移。而qemu本身是支持在线迁移的,包括设备状态和设备上的数据的在线迁移,但在使用vhost模式时是不支持在线迁移的。主要原因是使用了vhost之后qemu只控制了设备的控制链路,而设备的数据链路已经托管给了后端的SPDK,也就是说qemu没有设备的数据流IO路径所以并不知道一个设备那些部分被写入了。

在考察了现有的qemu在线迁移功能后,我们觉着这个技术难点并不是不能解决的,因此我们决定在qemu里开发一套针对vhost存储设备的在线迁移功能。

块设备的在线迁移的原理比较简单,可以分为两个步骤,第一个步骤将全盘数据从头到尾拷贝到目标虚机,因为拷贝过程时间较长,肯定会发生已经拷贝的数据又被再次写入的情况,这个步骤中那些再次被写脏的数据块会在bitmap中被置位,留给第二个步骤来处理,步骤二中通过bitmap来找到那些剩余的脏数据块,将这些脏数据块发送到目标端,最后会block住所有的IO,然后将剩余的一点脏数据块同步到目标端迁移就完成了。

SPDK的在线迁移原理上于上面是相同的,复杂之处在于qemu没有数据的流IO路径,所以我们在qemu中开发了一套驱动可以用来实现迁移专用的数据流IO路径,并且通过共享内存加进程间互斥的方式在qemu和SPDK之间创建了一块bitmap用来保存块设备的脏页数量。考虑到SPDK是独立的进程可能会出现意外crash的情况,因此我们给使用的pthread mutex加上了PTHREAD_MUTEX_ROBUST特性来防止意外crash后死锁的情况发生,整体架构如下图所示:

SPDK技术运用对RSSD云硬盘的优化路径

五 SPDK IO uring体验

IO uring是内核中比较新的技术,在上游内核5.1以上才合入,该技术主要是通过用户态和内核态共享内存的方式来优化现有的aio系列系统调用,使得提交IO不需要每次都进行系统调用,这样减少了系统调用的开销,从而提供了更高的性能。

SPDK在最新发布的19.04版本已经包含了支持uring的bdev,但该功能只是添加了代码,并没有开放出来,当然我们可以通过修改SPDK代码来体验该功能。

首先新版本SPDK中只是包含了io uring的代码甚至默认都没有开放编译,我们需要做些修改:

1.安装最新的liburing库,同时修改spdk的config文件打开io uring的编译;

2.参考其他bdev的实现,添加针对io uring设备的rpc调用,使得我们可以像创建其他bdev设备那样创建出io uring的设备;

3.最新的liburing已经将io_uring_get_completion调用改成了io_uring_peek_cqe,并需要配合io_uring_cqe_seen使用,所以我们也要调整下SPDK中io uring的代码实现,避免编译时出现找不到io_uring_get_completion函数的错误:

SPDK技术运用对RSSD云硬盘的优化路径

4.使用修改open调用,使用O_SYNC模式打开文件,确保我们在数据写入返回时就落地了,并且比调用fdatasync效率更高,我们对aio bdev也做了同样的修改,同时添加读写模式:

SPDK技术运用对RSSD云硬盘的优化路径

经过上述修改spdk io uring设备就可以成功创建出来了,我们做下性能的对比:

使用aio bdev的时候:

SPDK技术运用对RSSD云硬盘的优化路径

使用io uring bdev的时候:

SPDK技术运用对RSSD云硬盘的优化路径

可见在最高性能和延时上 io uring都有不错的优势,IOPS提升了约20%,延迟降低约10%。这个结果其实受到了底层硬件设备最大性能的限制,还未达到io uring的上限。

六 总结

SPDK技术的应用使得虚拟化IO路径的性能提升不再存在瓶颈,也促使UCloud高性能云盘产品可以更好的发挥出后端存储的性能。当然一项技术的应用并没有那么顺利,我们在使用SPDK的过程中也遇到了许多问题,除了上述分享的还有一些bug修复等我们也都已经提交给了SPDK社区,SPDK作为一个快速发展迭代的项目,每个版本都会给我们带来惊喜,里面也有很多有意思的功能等待我们发掘并进一步运用到云盘及其它产品性能的提升上。

 看了以上关于SPDK技术运用对RSSD云硬盘的优化路径,如果大家还有什么地方需要了解的可以在编程笔记行业资讯里查找自己感兴趣的或者找我们的专业技术工程师解答的,编程笔记技术工程师在行业内拥有十几年的经验了。

 

 


推荐阅读
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • 本文分析了Wince程序内存和存储内存的分布及作用。Wince内存包括系统内存、对象存储和程序内存,其中系统内存占用了一部分SDRAM,而剩下的30M为程序内存和存储内存。对象存储是嵌入式wince操作系统中的一个新概念,常用于消费电子设备中。此外,文章还介绍了主电源和后备电池在操作系统中的作用。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • MPLS VP恩 后门链路shamlink实验及配置步骤
    本文介绍了MPLS VP恩 后门链路shamlink的实验步骤及配置过程,包括拓扑、CE1、PE1、P1、P2、PE2和CE2的配置。详细讲解了shamlink实验的目的和操作步骤,帮助读者理解和实践该技术。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 本文由编程笔记#小编整理,主要介绍了关于数论相关的知识,包括数论的算法和百度百科的链接。文章还介绍了欧几里得算法、辗转相除法、gcd、lcm和扩展欧几里得算法的使用方法。此外,文章还提到了数论在求解不定方程、模线性方程和乘法逆元方面的应用。摘要长度:184字。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
author-avatar
椒桥头_671
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有