面向存储网络的融合I/O模拟器设计与实现①

2020-11-06 00:46黎斐南霍志刚孙凝晖
高技术通讯 2020年10期
关键词:存储设备模拟器队列

魏 征 黎斐南 邢 晶 霍志刚 孙凝晖

(*中国科学院大学 北京 100089)(**计算机体系结构国家重点实验室 北京 100089)(***中国科学院计算技术研究所 北京 100089)

0 引 言

存储设备在过去很长一段时间都被视为高延迟的慢速设备,随着新材料和设备的研制,存储设备的性能有了很大改善,I/O延迟大大下降。然而目前的大部分软硬件的设计还是建立在慢速设备的假设上,这种设计无法充分发挥新式存储设备的性能,因而仍存在读写延迟高的问题。

机械硬盘(hard disk drive, HDD)[1]作为主要的廉价存储设备,从最初的3.75 MB到现在的14 TB,HDD的容量增加了373万倍。但是,HDD的访问延迟从600 ms下降到了2 ms,只减少到了原来的1/300。HDD数据存储在盘片上,受机械结构的限制,碟片的旋转速度不能无限提高。HDD的平均延迟基本都是毫秒级的。固态硬盘(solid state drive, SSD)使用集成电路作为存储介质,受益于半导体工艺的发展,延迟可以达到微秒的量级[2]。现在的NVMe SSD可以达到几十微秒的延迟。基于3D XPoint材料的存储设备拥有更低的延迟,填补了SSD和内存之间的差距,其延迟达到微秒级[2]。

传统的跨节点数据通路中,数据传输都要经过内存。数据一开始在远程主机的内存中,中央处理器(central processing unit, CPU)设置网络接口控制器(network interface controller, NIC)的直接存储器访问(direct memory access, DMA),由DMA把数据发送到网络上。本地的NIC从网络收到数据,数据经过DMA的搬运,保存到内存中。然后CPU再控制存储设备的DMA,把数据写入本地的存储设备。随着存储技术的发展,存储设备的延迟已经从原来的毫秒级变为了现在的微秒级,数据在数据通路上延迟在整个传输延迟中的占比会大大增加,原来的传输路径可能会导致额外的传输开销。

NoR技术(NVMe over RDMA)[3]通过改变传统的数据传输通路优化延迟。本地网卡从远程主机接收到的数据不再写入内存,直接通过PCIe[4]总线写入本地的PCIe SSD。通信路径的改变使得传输延迟从12 μs缩减到了7 μs。缩短后的通信路径绕过了CPU,但也失去了对数据的处理能力。数据直接写入存储只能满足应用,很多其他应用都需要对数据进行一些处理,NoR技术即使是很简单的处理都无法完成。而且,只有存储设备是非易失性随机访问存储器(non-volatile random access memory, NVRAM)或随机存取存储器(random access memory, RAM)时,远程直接数据存取(remote direct memory access, RDMA)网卡才能直接给存储设备写入数据。NVRAM存储设备虽然拥有接近RAM的性能,同时造价成本也很高,而性价比较高的且真正大量使用的SSD采用的是NAND Flash介质,属于块设备,无法通过RDMA协议直接写入数据。如果希望能写入块设备,那么数据就需要经过闪存转换层(flash translation layer, FTL)的处理。

由于机械硬盘的高性价比,目前依然作为主流的存储设备使用。然而机械硬盘的随机延迟很高,为了充分发挥机械硬盘的性能,将随机读写组织成顺序读写作为主要优化方式。但是大数据的数据形式多样,数据的组织有可能很复杂,难以组织成顺序的读写。RAMCloud[5](内存云存储)把大数据应用所需求的数据全部存放在内存中,完全可以满足大数据分析的需求。但是RAMCloud的成本高昂,且由于持久化问题,还需要额外的成本和机制用于保障可靠性。机械硬盘和RAMCloud之间的性能和成本落差太大,SSD具有介于内存和机械硬盘之间的性能和成本。随着3D XPoint技术的推出,SSD拥有更高的存储密度和对随机高并发的支持。如果SSD的性能可以满足大数据分析的要求,可以有远小于RAMCloud的成本以及集群规模。

NoSQL数据库在大数据应用中有着很重要的地位,根据用户需求,弱化了SQL数据库的一些要求以满足大数据应用的场景。key-value存储是NoSQL数据库的一种典型案例,只保存最简单的key和value之间的映射。Redis[6]和Amazon的Dynamo[7]都是key-value存储系统的著名实例。本文的另一个重点就是尝试将SSD应用于大数据应用,为大数据应用提供一种存储解决方案。

本文设计了面向网络与存储的融合设备模型用户级融合I/O(unity I/O in user space, UIO),并加入辅助计算功能扩展其适用场景。本文的主要工作和贡献包括:

(1) 提出了一种融合存储和网络功能的UIO设备模型。UIO设备在同一种设备中融合了存储和网络功能,通过让多个功能模块共享设备中的内存和数据通路以简化数据的传输路径,降低数据的传输延迟。

(2) 设计了基于UIO设备模型的辅助计算模块。通过在设备中加入辅助计算功能实现数据处理,并把辅助计算模块分为处理设备间数据分布和存储介质格式转换2个部分。通过与可编程硬件的结合,可以让用户定制辅助计算模块,提高UIO设备的处理效率,扩展其应用场景。

(3) 实现了与key-value存储系统相结合的UIO设备模拟器。参照key-value存储系统设计了UTL和GME等各个模块,让用户可以通过put、get指令操作设备。在最终测试中与传统数据通路相比,远程put减少8.2%延迟,远程get减少11%延迟,本地put增加0.9%延迟,本地get增加2.7%延迟的效果。

1 相关研究

1.1 相关硬件技术

随着硬件技术的发展,已经有了高速低延迟的存储设备NVMe SSD。这种具有低延迟特性的存储设备的出现,使得传统的硬件结构不再适合所有场景,反而成为了系统性能进步提升的瓶颈。

1.1.1 SSD

SSD使用半导体作为存储介质,包括DRAM、NOR Flash、NAND Flash等。现在比较常用的是NAND Flash作为存储介质的SSD。NAND Flash的数据由浮栅单元存储,每个单元根据存储介质的不同(SLC, MLC, TLC)可以存储1、2或3个bits。由浮栅单元组成逻辑页,逻辑页组成逻辑块。一个页由4 kB数据存储空间和128BECC校验数据的存储空间组成,64个页又组成了一个块。页是NAND Flash中最小的读写寻址单元,块是NANDFlash中最小的可擦除单元。可以随意读取页中的数据或者向空白的页写入数据,但是不能改写已经写入页中的数据,如果改写需要将整个块的数据擦除,然后才能重新写入新的数据。

NAND Flash[8]的这种读写机制导致其读写接口不能使用常见的读(Read)和写(Write)接口,在读、写之外还需要加入擦除(Erase)功能。在Flash和传统接口之间需要添加一个转换层FTL[9,10],位于SSD的Host Interface和NAND Interface之间,负责2种接口之间的转换。FTL主要负责的功能有地址映射、磨损均衡、垃圾回收、坏块管理等。地址映射为主机使用逻辑地址定位数据,由FTL完成从逻辑地址到物理地址的映射。当数据修改时,把数据写到一个新的页上并修改FTL中记录的地址映射,以避免多余的数据读写。磨损均衡为Flash中每个存储单元的可写入次数是有限的,为了延长整个设备的使用寿命,尽量保证每个单元的写入次数均匀。FTL记录各个块的剩余寿命,尽量使用寿命长的块。同时,也会把一些存储在剩余寿命比较长的块中但是不经常改动的数据搬移到剩余寿命较短的块中。垃圾回收是在NAND Flash中,以块为单位擦除,失效的页空间不会立刻释放。而垃圾回收负责释放失效的页,保证空间利用率。它会把一个块中还有效的页复制到其他块中,然后擦除整个块。坏块管理会记录下已经无法使用的块,在写入数据时避开。

1.1.2 NVMe协议

SSD中除了存储介质和控制器还有一个关键的组成部分就是主机接口。以Intel为代表的厂商联合推出了专为PCIe SSD设计的协议NVMe[11]。NVMe协议专为SSD设计,最大支持64 k个队列,每个队列可以容纳64 k条指令,使用多队列和doorbell的方式读写指令,不需要对队列加锁,可以充分发挥高性能SSD设备的性能。PCIe接口解决了SSD主机接口的硬件通路瓶颈问题,NVMe协议解决了SSD主机接口的软件协议瓶颈问题。

NVMe协议中的队列分为Admin Queue和I/O Queue。每类队列又分为提交队列(submission queue,SQ)和完成队列(completion queue,CQ)。Admin Queue负责对设备的管理,完成创建删除队列、设置参数、查询日志等工作,I/O Queue负责具体的传输指令,完成Read、Write、刷回(Flush)等操作。SQ用于主机向设备发送指令,CQ用于设备向主机发送指令的返回结果。一个CQ可以匹配多个SQ,通过SQ和CQ的配合完成对设备的操作。

1.1.3 RDMA网卡

以太网网卡在接收数据时,数据必须经过系统的处理才能提供给需要这个数据的应用。这种处理增加数据传输延迟的同时也增加了CPU的负担,在网卡的性能越来越高的同时,对CPU的性能也提出了挑战。

基于解决数据在内存和设备之间的数据传输,并减轻CPU负担的DMA机制,RDMA被提出并用于解决网络传输的问题[12-17]。RDMA通过网络直接把数据传入主机的用户空间,不再需要内核参与,提高了网络传输性能,降低了CPU的处理负担。在RDMA的Infiniband网卡中,具有和NVMe协议中类似的队列结构,其中有Send Queue,Receive Queue和Completion Queue。Infiniband网卡的设计目的就是为了提高网络性能降低传输延迟,使用的场景通常也是对网络有着很高要求的应用,同时也需要高性能的队列结构避免在处理I/O请求时成为瓶颈。

1.2 设备融合

数据在不同设备之间传输所消耗的时间一直是研究者们尽力减少的,如果一种设备可以同时完成2种工作,那么数据只要在设备内部流动,不需要跨设备的传输。针对不同的设备类型和不同的使用场景,已经有了一些通过设备融合优化系统性能的研究。

1.2.1 存储和计算的融合

XSD(accelerator SSD)[18]通过在SSD中加入嵌入式图形处理器(graphics processing unit, GPU)以提供计算功能,并为用户提供了易用的Map-Reduce[19]接口。XSD在SSD中插入了嵌入式GPU,和SSD原有的嵌入式CPU共享内存空间。XSD通过流水化来避免数据拷贝时间的浪费。由于Flash控制器和GPU是共享内存的,Flash向动态随机存取存储器(dynamic random access memory, DRAM)写入数据的同时GPU也在从DRAM中复制数据进行计算再把数据写回DRAM。XSD通过流水化避免了GPU对数据的等待问题,充分利用了GPU。XSD通过在SSD内使用嵌入式GPU加速计算,通过计算的流水化充分利用了SSD和GPU的性能,通过采用Map-Reduce编程框架提供简单高效的设备使用接口。虽然在SSD中加入计算设备可以有效减少设备等待数据传输的开销,但是因为嵌入式设备自身性能问题,其性能提升能力还是有所不足的。

1.2.2 存储、网络和计算设备的融合

BlueDBM[20]是具有Flash存储系统、存储端计算引擎和网络功能的PCIe设备。其中,Flash存储系统直接开放原始的flash接口(也就是不使用FTL层),由系统层管理数据。BlueDBM通过提供多种软件接口(文件系统接口、块设备接口和加速器接口)以方便用户对设备的使用。BlueDBM在图遍历测试的性能(ISP-F)虽然比使用DRAM的方案(H-DRAM)要差,但是当数据只能部分装入内存时(50%F,30%F),BlueDBM的性能已经足以替代DRAM。BlueDBM通过对Flash存储介质的直接控制和存储端的计算能力在多个测试中取得了优秀的结果。但是BlueDBM采用了使用固定配置文件的方式,不具有扩展能力。虽然提供了多种Flash存储的操作接口,但没有提供操作设备的存储、网络和计算功能的统一接口,用户需要十分了解BlueDBM的结构才能使用。

1.2.3 存储和网络的融合

NVMe over Fabric[3]就是一种在共享NVMe SSD资源的同时尽量减少额外开销的方案。资源池化,可以让多台计算机共享存储资源,提升扩展性和资源的利用率,降低成本。NVMe over Fabric分离了NVMe设备的前后端,前后端之间通过RDMA网络传输。前端可以把internet小型计算机接口(internet small computer interface, iSCSI)协议转换为NVMe的协议,让系统统一可以使用NVMe over Fabric。通过网络可以很容易地扩展存储,想要更大存储容量时只要添加存储设备,不需要扩展机群规模。同时,因为RDMA网络有着低延迟,NVMe over Fabric对数据传输延迟的影响很小。测试表明,通过NVMe over Fabirc使用远程NVMe设备时,读写的IOPS(input/output operations per second)几乎不受影响,传输延迟的增加也低于8 μs。但是NVMe over Fabric只是对NVMe存储的扩展,缺少计算能力。NVMe over Fabric虽然可以改善主机读写远程存储时的延迟,但是在数据需要处理时仍然无法改善数据路径冗余导致的浪费。

2 UIO设备模型

在传统计算机硬件中,存储和网络设备往往是独立的2种设备,而且数据无法直接在这2种设备之间传输,必须经过CPU和内存。随着硬件技术的发展,存储设备和网络设备的延迟越来越低,数据无法在设备之间直接传输导致的额外延迟在传输延迟中的占比也越来越高,这导致新式I/O设备无法充分发挥其性能。通过设备融合,让同一设备具有存储和网络功能,设备内部的存储和网络模块可以直接通信,避免数据在通路上的性能损失,减少通信的延迟开销,改善系统整体性能。

2.1 UIO设备结构

如图1所示,UIO设备是插于PCIe卡槽的I/O设备,同时具有存储设备和网络设备的功能,为了提供一定的数据处理能力,UIO设备还具有辅助计算功能。与SSD和网卡一样,UIO设备需要系统中的驱动程序支持,由驱动程序负责与设备的通信。

图1 UIO设备在系统中的位置

如图2所示,UIO设备中具有指令队列、指令处理、DMA、DRAM、存储模块、辅助计算模块和网络模块。

图2 UIO设备模块设计

指令队列结构NVMe SSD和RDMA网卡都是具有高吞吐量和低延迟的高性能I/O设备,这2种设备都使用了高性能的I/O指令队列作为主机接口。UIO设备的设计目标是解决高性能I/O设备的传输延迟问题,为了支撑设备的高性能,采用了队列结构。基于并发性考虑,管理队列为每个应用建立独立的指令队列。管理队列为不同的程序创建完队列并分配好权限后,应用有读写需求时只需要向自己的队列中写入指令即可。设备会从指令队列的空间读取指令,因为I/O队列的权限已经由管理队列设置好,可以由设备检查指令是否符合该指令队列的权限,而不需要内核的处理。这为用户级I/O和虚拟化提供了方便。

指令处理指令处理要完成2部分工作,一个是指令仲裁,一个是指令解析。UIO设备具有多对指令队列,不同进程使用设备时不必给队列加锁,每个进程都可以自由地给设备发送指令。设备上有相应的模块来处理多个指令队列之间的协调调度问题,这个功能就是指令仲裁。指令仲裁会决定设备执行的下一条指令是什么。执行的顺序通常由队列的优先级决定。指令解析会把指令翻译成设备内部模块的控制信息,而设备的其余模块才是真正完成数据传输工作的部分。

DMA设备在解析完指令后,执行对应的数据传输,即主机和设备之间的数据传输。UIO中DMA主要负责把主机中数据传输到DRAM中,而数据从设备到主机的传输会根据实际情况由不同的模块完成。

DRAMUIO中的DRAM有2个作用,一个是保存设备运行时必要的信息,一个是作为数据传输的缓存和缓冲。一般的存储设备,读写速度和延迟都是不一致的,Flash介质的存储设备还存在写放大的问题,FTL正在执行的一些任务(例如静态磨损均衡和垃圾回收)也会导致读写时间出现较大波动。为了提供更好的设备性能,设备中的DRAM可以作为读写的缓存。UIO中网络传输到设备中的数据,也需要一些内存空间进行缓冲,平衡存储模块和网络模块读写速度的差异。

2.2 可编程模块

在UIO设备中,需要具备存储、网络和辅助计算3种功能,如何使用这3种模块是提供高性能的关键问题。

2.2.1 模型分析

基于独立设备接口的指令接口用户需要控制各个模块对数据的处理,以及数据在各个模块之间的传输。用户使用设备的自由度高,通过精心设计的指令可以充分发挥设备的性能。但是,这种方案在实际使用中会有很大的局限。首先,处理器的性能受功耗限制,在I/O设备中嵌入的处理器性能有限。如果向用户提供全功能的通用计算处理器,处理器的性能可能无法匹配高速I/O设备的性能,反而成为性能瓶颈,带来过多的性能损失。其次是I/O设备的接口复杂性。对Flash的读写不能使用传统的Read和Write原语,而要使用编程(Program)、Read和Erase的原语进行读写。SSD中通常用FTL层进行这2种接口的转换。如果向用户开放Flash的原始接口,那么FTL负责的功能都需要用户来完成。这会极大提高用户的使用难度,用户除了要熟悉Flash的接口还要进行复杂的性能优化,难以发挥高性能存储的能力[21-27]。

基于需求抽象分析的统一指令接口UIO设备采用的方案是抽象出用户需求,根据用户需求设计专用设备,向用户提供统一的指令接口,用户通过使用统一的指令就可以完成对设备全部功能的操作。这种方案的缺点显而易见,设备的功能受限,只能在特定场景下使用。但是这一缺点可以通过抽象用户需求弥补。可以通过分析用户使用较多的场景,把某一类用户的需求提取出来,然后制作设备专门用于满足这类用户的需求。虽然无法满足所有用户的需求,但是通过抽象出多种用户的需求也足以覆盖大部分用户。

统一的用户指令使用简单,通过抽象用户需求,可以向用户提供具有高级语义的接口,完全屏蔽设备实现的具体细节。甚至可以根据为用户提供的功能深度定制底层模块的逻辑。如图3所示,移除了原有设计中的辅助计算模块,改为统一转换层(unity translation layer, UTL)模块和全局信息管理引擎(global management engine, GME)模块。UTL模块和GME模块都是可编程模块,可以根据用户需求写入不同的处理逻辑。其中,UTL模块负责读写存储介质,GME负责分离本地和远程的传输。

图3 UIO模块设计专用方案

2.2.2 UTL模块

UTL模块用于取代SSD中的FTL模块,负责实际的存储介质的读写。UTL把用户对设备的操作接口转换为对Flash介质的Program、Read和Erase接口,UTL提供可编程的接口。UIO针对抽象出来的用户需求,完成特定类型的操作,针对Flash存储介质的特点,完成用户定义接口到flash介质接口的高效转换。

2.2.3 GME模块

GME模块负责多个设备之间的通信,通过增加设备的数量进行扩展,通过多个UIO设备的协同工作,共享存储空间,扩展各UIO设备的性能。

如图4所示,把多个设备映射到一个全局空间中。用户通过本地设备的接口就可以透明地操作全局空间,而不必感知到其他设备的存在。当系统中增加设备时,用户看到的是全局空间的扩展。GME控制数据的分布,并根据数据的分布规则把数据发送到相应的设备。如果是本地的数据就交给UTL模块处理,由UTL模块写入本地的存储介质;如果是远程的数据就通过网络模块发送到目标设备,由目标设备写入存储。

图4 UIO设备多机模型

2.3 基于UIO的应用示例

2.3.1 key-value存储

在key-value数据库中,哈希存储方式把KV对组成的记录顺序写入存储介质,在内存中建立从key到记录地址的映射。在读取时就根据映射地址读取;修改时写入一条新的记录,然后修改内存中映射的地址;删除时并不删除实际的记录,而是写入一条代表已删除的记录。为了支持更好的扩展性和并发性,在UIO中,可以进行2次哈希存储,一次由GME进行,把数据分布到不同的设备上,一次由UTL快速定位数据在存储介质中的位置。哈希存储虽然实现简单,查找效率高,但是只能查找单条记录,如果想查找一个范围内的数据效果比较差,此时需要考虑顺序分布的存储方式。

如图5所示,顺序分布把key分为多个范围,不同范围的数据组成不同的子表,Root表记录每个子表存储在哪个节点中。在UIO设备中,可以由GME记录每个子表的数据范围和节点信息,在查找范围时由GME把大的范围转换为对多个子表的查询,UTL则负责一个子表,根据查询返回结果。

图5 顺序分布

2.3.2 图片检索

图片检索功能就是向UIO设备发送图片后,UIO设备从存储中检索出相似的图片并发送给主机。其中,GME模块负责把图片分发给本地UTL模块和其他远程设备。所有UIO设备中的UTL模块收到图片后就会读出存储中的图片,并进行比对,并把相似的图片发送给源设备。源设备收到图片后会发送到主机。与传统方案中数据需要在存储设备和CPU或GPU通信相比,由专用的硬件模块处理图像可以取得更高的运算效率。在存储设备中的比对使得大部分数据都不需要从设备传输到主机,只需要传输比对后相似度高的图片,设备和主机间的带宽可以用来传输远程设备传输过来的图片,避免了带宽的浪费。

2.3.3 kNN算法

最邻近结点(k-nearest neighbor,kNN)算法是一种常用的机器学习算法,通过计算未知数据和已知数据的“距离”来预测未知数据的类别。kNN算法在预测时会取出已知数据中和待预测数据最接近的前k项数据作为预测的样本,这也是kNN算法中k的含义。UIO在处理kNN算法时,存储介质中存储所有的样本。在主机向设备发送待预测样本后,GME模块把样本发送给所有设备。所有设备的UTL模块接收到样本后,会读出存储介质中的样本并计算距离值,在计算的过程中保存最接近的前k个值。全部的值比对完成后设备会把前k个最接近的结果发送给源设备,源设备的GME模块在收集到所有设备的返回结果后会进行排序并选出其中的前k个值预测分类,再把分类结果发送给主机。

3 UIO模拟器实现

为了验证UIO设备的设计是否有效,并为将来UIO设备的相关研究提供验证平台,本文将实现UIO设备的模拟器。

3.1 整体架构

如图6所示,UIO设备模拟器的结构依照UIO设备的基本结构而设计。由指令队列和控制寄存器共同组成设备接口。其中指令队列分为Admin Queue和I/O Queue,每种Queue又由SQ和CQ组成。除了指令队列,主机还需要一些寄存器为设备进行初始化以及保持状态信息。在实际UIO设备模拟器的实现中,本文选择的目标是实现采用key-value接口,使用put/get指令,GME模块和FTL模块都采用哈希分布。

图6 UIO设备结构图

UIO设备模拟器是用户态功能级的模拟器,目标是验证UIO设备的模型是否有效。在UIO模拟器的设计中,首先进行初始化工作,然后创建2个线程,一个模拟主机端,一个模拟设备端。主机端会接收来自控制台的命令,并把用户的命令转换为相应指令写入设备端的控制结构。设备端则是根据控制结构中的指令执行实际的操作,从主机端复制数据或者向主机端写入数据并根据指令执行情况提供返回结果。设备端启动后会创建出指令处理、DMA、GME、UTL和网络通信(network communication, NET)一系列线程用于模拟UIO设备中的各个模块。考虑各个模块的运行都是并行的,采用多线程来尽量接近真实的设备特性。

3.2 UIO设备接口设计与实现

UIO的设备结构主要借鉴了NVMe的设备接口设计,并根据UIO设备的特性进行了修改。

3.2.1 指令设计

在UIO中,本文设计了2种指令,Admin Command和IO Command。出于简化设计突出原理的目的,只设计了实现UIO最核心功能的指令。Admin Queue的4种操作就是创建和删除SQ和CQ。需要注意的是,在创建SQ前应该先创建SQ所对应的CQ。如果先创建了SQ又向队列中写入了指令,设备在处理完指令后找不到应该写入返回结果的CQ就会导致未知的结果。IO Command只有put和get 2条。put提供key和value,表示把key的值更新为value。get提供key,表示读出key存储的值。

如表1所示,每一条指令有64个字节组成。其中,opcode用于指明要执行的是哪条指令;cid是指令的表示,使用队列的id加cid可以确定唯一的一条指令;nsid用于指明该条指令用于操作哪个namespace,为不同用户和应用的操作系统硬件级的隔离(在改版UIO中尚未实现,只是预留接口);其余部分会根据指令的不同有不同含义或者是保留字段。

表1 指令格式

例如在Create IO Submission Queue的指令中,adr2用于保存队列的起始地址;cdw10用于保存队列大小和队列id;cdw11中保存SQ对应的用于放置返回结果的CQ的队列id以及该SQ的优先级。

而在put和get指令中,adr1用于存放key的地址,len1存放key的长度,adr2用于存放value的地址,len2用于存放value的长度(get指令中实际上是主机为get的返回值创建的缓冲区的地址以及缓冲区长度)。

表2所示是CQ中返回项的格式。Command Specific是指令的返回结果,根据指令的不同也有所不同;SQ Identifier是发送该指令的SQ的id,SQ Head Pointer指明返回该指令时,设备中维护的SQ的Head Doorbell指向的位置(在主机读取到时设备中该值可能已被更新);Status Field返回指令执行的基本信息,例如是否成功,是否可以继续尝试;P是Phase Tag,Phase Tag只有1位,用于指明该返回项是否已经填写完成;Command Identifier就是该返回项对应的指令的id,前面提到队列id加指令id的

表2 CQ返回项格式

组合可以确定一条指令,也就是说,主机根据这2个id就可以知道完成的是哪条指令了。

3.2.2 BAR寄存器

基地址寄存器(base address register, BAR)解决的是最基本的主机与设备通信的问题。主机所看到的BAR寄存器是内存中的一段空间,主机通过读写其中的数据实现对设备的控制。UIO设备的BAR寄存器参照了NVMe的设计,主要使用了其中关于Admin Queue的AQA、ASQ、ACQ以及Doorbell部分的寄存器,如表3所示。

虽然主机和UIO设备的主要通信方式是通过指令队列,但是这就需要知道指令队列的地址。IO Queue的地址空间是由主机在内存中申请并通过Admin Queue指令把地址提供给设备,由设备自行从主机内存中获取指令。这就需要主机和设备都统一预先知道Admin Queue的地址。而这个地址就是由BAR寄存器提供的。BAR寄存器中的ASQ和ACQ分别提供了Admin Submission Queue和Admin Completion Queue的起始地址。AQA则提供了Admin Queue的大小。之后的CQ0TDBL和CQ0HDBL等寄存器则分别提供了SQ的Tail Doorbell和CQ的Head Doorbell。Head和Tail Doorbell是2个指针,分别指出了指令队列中存放有数据部分的起始和结束。

基于Queue的起始地址(Admin Queue的在BAR寄存器指出,IO Queue的由主机和设备分别自己维护)和Doorbell,主机就可以完成对设备的控制,设备就可以获得主机的指令,完成自己的工作了。

表3 Bar寄存器定义

3.3 UIO设备模拟器控制结构的实现

3.3.1 指令仲裁

由于指令优先级和UIO模拟器要验证的原理关联不大,UIO模拟器中的指令队列只使用了1级优先级,指令仲裁使用轮询的方式从队列中取指。

UIO中会为所有队列建立一个链表,维护每个队列的Head和Tail,每当队列创建时就加入该链表,队列删除时就从中释放。指令仲裁通过检查Head和Tail判断队列是否为空,如果队列不为空就从队列中取出Head所指向的指令并交给指令解释器执行。在取出一定条数的指令后,或者队列为空时,就通过next指针找到下一个队列。

3.3.2 指令解释器

指令解释器首先根据取指的队列id判断是Admin Command还是IO Command。然后从指令中取出opcode字段,根据opcode判断是哪条指令并根据该指令的字段解析其中有用的信息,并把这些信息发送给数据处理模块。

在处理Admin Command的时候,因为不涉及数据的传输,由指令解释器执行具体的指令。在创建队列时,指令解释器会创建图7中的队列轮询控制结构,并指向指令中给出的地址;而在删除队列时,指令解释器会释放队列的控制结构。

图7 UIO队列轮询结构

3.4 数据处理模块

UIO模拟器采用消息队列模拟模块间的通信,包括指令解释器模块向数据处理模块发送的请求和数据处理模块之间发送的请求。模块间消息队列只有请求项不设返回值,当模块处理指令成功或者失败时,会根据处理情况向Completion Queue填写返回信息以完成对指令的处理。

3.4.1 DMA模块

在UIO模拟器中,DMA负责把数据从主机内存中复制到设备的内存中,以供后续其他模块处理。当指令是put时,DMA会复制key和value;当指令是get时,DMA会复制key。

DMA将数据组织成如表4所示的记录形式,以方便传输或者写入Flash颗粒。校验码是由数据内容计算出来的固定长度的字段。因为Flash存储技术自身的缺陷,存储单元中的数据过一段时间后可能会失效或者改变,通过错误检查和纠正(error correcting code, ECC)保证数据可以完整正确地读出。在网络传输和key-value数据库中,一般也会加入校验字段来验证数据的有效性。

表4 记录结构示意图

UIO模拟器中的DMA只负责从主机端读取数据到设备DRAM中,从设备中读取数据到主机端的工作则交给其他模块完成。存储介质的写入速度或者向远程设备发送数据的速度都低于写入DRAM的速度,用DRAM作为缓存提高效率。但是从设备中读取数据时,可以由设备内模块直接向主机内存传输。

3.4.2 GME模块

GME负责把数据的读写请求根据key把指令分配到不同的设备上。如图8所示,GME模块收到请求后会读出其中的key,然后计算key的哈希值,并在映射表中查找该哈希值对应的目标服务器id。如果指令目标是本地设备,就交给UTL模块处理,如果指令目标是远程设备就交给NET模块处理。GME模块中的映射表可以通过分布式协议获取,也可以通过配置文件写入,UIO模拟器中是通过函数计算哈希值和目标设备id之间的关系。

图8 GME模块原理示意图

3.4.3 UTL模块

在UIO模拟器中通过建立Flash颗粒的块和页2级来模拟Flash介质的基本性质。Flash颗粒中,页只能被写入不能改写,修改引起的拷贝复制导致写放大问题。如图9所示, UIO模拟器借鉴了键值存储系统的处理方式,创建1条新的记录,顺序写到现在记录的尾端把原有记录视为失效。当1个页完整写入后只读取不再改动。块是由页组成的,当1个块中所有页都被写入后会成为固定块,不再发生改动。

UIO提供key-value接口,UIO接收的指令不包含地址,UIO仿照FTL实现key到物理地址的映射。UTL会在DRAM中建立哈希映射表,哈希表通过key来索引value保存的具体位置,其中包括block id、page id、value位置和长度。当发生写请求时,UTL就把记录顺序写入Flash中,然后根据写入时的地址更新内存中的哈希表;当发生读请求时,先从哈希表中查询到value的地址,然后再从Flash中定位并读出数据。当请求是来自本地时,UTL就可以直接把返回结果写入本地设备的Completion Queue并把数据写入主机内存。当请求是来自远程时,UTL就把数据暂存在设备的内存中,并给NET模块发送请求,由NET模块处理。

UTL对块进行定期扫描,进行垃圾回收,提高空间利用率。UTL从头到尾扫描块,从中读出每一条记录的key,并把记录地址和该key在哈希表中指向的地址进行对比。如果是同一个地址说明该记录是有效的,UTL就把该记录写入到活动块中继续保留;如果该记录的地址和哈希表中的不一致,说明该记录已经失效,直接跳过即可,扫描完整个块,该块就可以擦除回收了。

图9 UTL哈希表示意图

3.4.4 NET模块

NET模块由2部分组成,分别负责发送、接收网络请求。Send流程中会有4种情况,远程put请求、远程get请求、远程put回复、远程get回复。其中,远程put和get请求是来自GME的指令,GME根据key判断指令目标是远程设备时,会向NET模块发送指令并告知目标设备id,由NET模块负责发送。其中,put请求需要向远程设备发送key和value,get请求需要发送key。

远程put、get请求的接收,都接收到设备内存中,由UTL模块处理。远程设备把put和get请求处理完后会发送回复,对于put的回复只要知道put指令执行的状态即可,获得结果后向CQ填写返回结果这条指令就完成了。而远程get指令是有查询结果的,设备接收到结果后还要复制给主机,等复制结束后就可以填写返回结果了。

3.5 指令整体流程

在主机写入指令后,指令仲裁把指令从指令队列中取出并送入指令解释器,指令解释器解析指令后给DMA发送控制信号,然后就由数据通路模块执行。

3.5.1 put指令

put指令,主机会提供key和value的地址和长度,DMA根据地址和长度分别从主机内存中复制key和value的值到设备内存中,并存储成记录的格式,然后向GME模块发送信号。GME模块会从设备内存中读出key,并计算key的哈希值,根据哈希值在内存中的映射表查找目标设备的id。

如果目标设备是本地设备,那么GME模块就向UTL模块发送请求,UTL在收到请求后从设备内存中读出记录并写入介质,并把写入到介质中的地址存到设备内存中的映射表。完成写入后,UTL模块会向CQ填写完成信息。如果目标设备是远程设备,则由NET模块负责处理。NET模块收到控制信号后会把内存中的记录分解为多个包并填写元数据以便于传输,然后向目标设备依次发送数据包。目标设备的NET模块收到数据包会读取数据包的opcode,如果判断出是put请求就会依次接收包并重新组成记录的格式,然后向UTL模块发送信号。UTL模块接收到信号后会把内存中的记录写入存储介质并修改内存中的映射表,然后向NET模块返回完成信息。NET收到完成信息后会发送到源设备,源设备的NET模块收到完成信息后会向CQ填写完成信息。

3.5.2 get指令

get指令的过程和put指令的过程大体相似,这里只介绍其中有区别的部分。DMA在执行get指令时只会从内存中复制key(因为指令中传递的value地址是应用申请好的缓冲区地址和长度)。

UTL在收到信号后会先从映射表中查找key所对应value在存储介质中的地址,根据这个地址找到value并复制到主机内存(因为主机内存的带宽和延迟一般都优于存储设备,所以直接复制也不会有性能问题还可以减少开销),然后填写返回信息。NET模块在向远程设备发送信息时发送的只有key,远程设备在返回完成信息时还要发送查询到的value的值。同样,本地设备的NET模块在接收到value的值后会直接复制到主机内存中。

4 测评与分析

4.1 测试环境与测试方案

4.1.1 测试环境

UIO模拟器的测试是在一台服务器上完成。服务器的配置如表5所示。UIO的测试采用在单台服务器上运行多个模拟器程序。由于程序之间通过Linux系统提供的消息队列进行通信,使用内存模拟存储介质,硬件只用到了CPU和内存。

表5 测试环境参数表

4.1.2 测试方案

UIO的设计目的是减少远程数据传输在设备和内存之间传输导致的额外延迟。为了进行对比测试,在UIO模拟器添加了一种模式,让UIO模拟器模拟传统的数据通路,在接收到数据后复制到主机内存中,再从主机内存重新读入设备,写入存储介质。除此之外,UIO模拟器在处理指令时会有一些额外开销。例如GME模块会验证指令是发往本地还是远程,传统存储设备中所有指令都是写入本地存储,并没有此项开销。所以用UIO模拟器模拟数据无需经过GME模块直接读写UTL模块的场景,测试UIO模拟器在本地模式下的额外开销。

4.2 数据传输延迟测试

在具体的测试中,会使用多种value长度(从4B到16 kB)的指令,其中的key和value都会使用英文字母填充。

4.2.1 UIO模拟器与传统数据通路对比

在图10和图11中,可以看出传统通路的指令执行延迟都高于UIO设备,根据指令长度的不同会多出10~30 μs。延迟的增加主要是因为数据复制和设备间的数据包导致,而传统通路的数据复制次数多于UIO设备,所增加的延迟也高于UIO设备。put指令中,value的长度越长执行延迟越长与UIO模拟器的实现方式有关,在使用put指令时因为需要向设备写入数据,模拟器在实际运行时需要向系统申请空间,所以越长的指令执行时间也越长。但是这部分时间的增量在2种通路都是存在的,并不会影响结论。测试结果表明,UIO设备路径与传统数据通路相比,远程put减少8.2%延迟,远程get减少11%延迟。

图10 UIO设备与传统通路远程put指令延迟对比

图11 UIO设备与传统通路远程get指令延迟对比

4.2.2 UIO模拟器与本地数据通路对比

对于本地put指令,可以看到有的指令是UIO的延迟更长,有的是UIO的延迟更短。大多数的数据差距都在2~3 μs内,差距在于UIO设备中需要额外经过GME模块计算目标设备id,对于3 μs左右的延迟这种随机波动影响很大,因此UIO设备和传统设备在运行本地put指令时开销基本相当。对于本地get指令,可以看到UIO设备的执行延迟基本超过传统通路,但是超过的幅度很小,基本在10 μs左右。如图12和图13所示,测试结果表明,UIO设备路径与传统数据通路相比,本地指令的差距基本不随value的长度变化,这是因为GME的操作是从设备内存中读取key,并计算key的Hash值,没有复制数据的操作。在实际使用中key的长度较小,所以Hash值的计算开销也不高,开销的变化通常也不大。

4.3 数据分析

从4.2节中可以看出,UIO设备在执行远程指令时延迟小于传统通路,而在执行本地指令时略微高于传统通路。

图12 UIO设备与传统通路本地put指令延迟对比

对于远程指令,传统通路中需要把指令从设备复制到主机中再从主机复制到设备中,相比UIO设备各个模块可以共用内存相比,增加了数据复制的开销,这部分开销造成了传统通路的额外延迟。而对于本地指令,UIO设备相比传统通路增加了GME计算指令的目标设备是本地设备还是远程设备的开销,这部分计算主要是使用哈希函数计算哈希值,再根据哈希值查表,都是开销比较小的计算,所以相比传统通路时间延迟增加并不显著。

如果设UIO设备减少的远程指令开销比例是a,增加的本地指令开销比例是b,UIO设备有N块,设备的能力都是相同的,哈希函数可以把数据均匀分布到N块设备上,那么用户的数据会有1/N在本地设备,(N-1)/N在远程设备,UIO设备相比传统通路的开销比值是

(1)

5 结 论

现有系统中,数据发往远程计算机存储设备的数据通路经过本地网卡、远程网卡、远程内存最终到达远程存储。数据无法直接在网卡和存储设备之间传输,导致了额外的传输延迟。新型高速存储介质的出现,存储设备的访问延迟大幅下降,使得这段延迟在整个传输过程的延迟中占比大大增加。为了降低数据传输延迟,充分利用新式存储设备的性能,本文设计了面向网络与存储的融合设备模型,提出了融合存储、网络和辅助计算功能的融合I/O设备。通过在同一设备中融合存储和网络功能,使得设备内的网络模块可以直接与设备内的存储模块通信,简化了数据的传输路径,降低了数据的传输延迟。实现了与key-value存储系统相结合的UIO设备模拟器。在最终测试中与传统数据通路相比,远程put减少8.2%延迟,远程get减少11%延迟,本地put增加0.9%延迟,本地get增加2.7%延迟的效果。

猜你喜欢
存储设备模拟器队列
了不起的安检模拟器
盲盒模拟器
划船模拟器
队列里的小秘密
基于多队列切换的SDN拥塞控制*
在队列里
丰田加速驶入自动驾驶队列
Windows 7下USB存储设备接入痕迹的证据提取
基于Flash芯片的新型存储设备数据恢复技术研究
动态飞行模拟器及其发展概述