问题
持久存储器(PM)具有接近DRAM的性能和数据持久性,配备PM的平台支持异步DRAM刷新(ADR)功能[2],确保PM DIMM的内容以及已到达内存控制器的写挂起队列(WPQ)的写入在电源故障时仍然有效。但CPU缓存中的写入仍然是不稳定的,需要明确的缓存行刷新指令和内存屏障来保证数据的持久性。
最近,名为扩展ADR(eADR)的新功能可用于PM平台[3],eADR保证CPU缓存中的数据在崩溃后可以刷新到PM。确保了CPU缓存中数据的持久性,并消除了昂贵的同步刷新。eADR的出现为构建无锁数据结构和释放PM的全部潜力提供了独特的机会。
现有方法局限性
-
现有的持久索引并发效率低下。锁在持久索引中广泛使用,因为现有的原语不能在基于ADR的平台上原子地修改和持久化数据。原子CPU硬件原语,如Compare-And-Swap(CAS),可以原子性地修改数据,但不能保证其持久性,因为CPU缓存是易失的。因此,如果没有锁,在另一个线程进行依赖读取之前,存储可能没有持久化,导致脏读。eADR缩小了CPU缓存中数据的可见性和持久性之间的差距,确保线程始终读取持久性数据,为开发高效无锁数据结构提供机会。
-
现有的持久索引给PM访问带来了很高的开销。之前方法通过减少缓存行刷新指令的数量来降低PM开销,因为数据刷新是基于ADR的PM系统的主要瓶颈[7]。使用eADR后,不需要向PM进行显式数据刷新。然而,索引操作和内存管理中的PM访问阻碍持久索引的有效性,因为PM的读取延迟比DRAM高,带宽比DRAM低[17,18,19]。特别是对于写操作,由于CPU缓存容量有限,脏缓存行最终将被写回PM,这会消耗稀缺的PM写带宽。为了充分挖掘具有持久CPU缓存的PM系统的潜力,需要进一步提高缓存利用率,并尽量减少持久索引中的PM访问。
本文方法
本文提出了NBTree,一种无锁、PM友好的B+树,以提供高可扩展性和低PM开销。
-
为了高可扩展性,提出无锁的并发控制协议。对于叶节点操作,采用日志结构的插入和原地更新/删除,结合CAS原语,支持无锁访问。当插入的叶节点已满时,用新叶节点替换旧叶节点,并通过结构修改操作(SMO)保持节点的平衡。NBTree提出了三种新技术(三阶段SMO、写同步和读同步)来处理叶节点无锁访问期间的潜在异常:(1)叶节点的并发更新和删除导致的更新丢失。利用三阶段SMO和写同步来解决。在SMO期间对叶节点进行更新或删除时,原地修改旧叶节点,修改要么通过三阶段SMO被动迁移到新叶节点,要么使用写同步主动同步到新叶节点。(2) 并发搜索操作导致读取不一致。无锁搜索可能会读取未提交的脏数据或过时数据,使用读同步来检测和解决。为了减少尾延迟,提出了协作SMO,使对同一SMO叶节点的并发插入协同工作。对于内部节点操作,应用硬件事务存储器(HTM)[20]来实现原子写入。同时设计了移位感知搜索算法,以确保无锁内部节点搜索到达正确的叶子。
-
为了减少PM开销,尽量减少了PM访问,并提高PM写入的局部性。采用解耦的叶节点架构来减少索引操作中的PM行访问,将叶节点的元数据和键值对解耦,元数据层与内部节点一起存储在DRAM中,PM只包含键值层。提出了缓存持久分配器(Calloc),以增强持久内存管理元数据修改的局部性。Calloc采用全局分配位图、回收的环形缓冲区和可回收日志,充分利用持久CPU缓存来吸收分配、释放和日志记录过程中发生的大部分PM写入,从而节省PM写入带宽。同时,NBTree采用日志结构的插入和就地更新来提高NBTree中写入操作的局部性,减少偏斜工作负载中的PM写入。
评估表明,在YCSB工作负载下,NBTree的吞吐量比最先进的持久B+树高11倍,99%尾延迟低43倍。
总结
针对DRAM和PM结合的场景,由于DRAM中缓存无法持久化,必须同步刷新到PM中,新推出的eDAR功能,该功能保证CPU缓存可以在崩溃后刷新到PM中。本文利用eDAR,提出了NBTree,无锁、PM友好的B+树,以提供高可扩展性和低PM开销。包括两个技术:(1)高可扩展性,提出无锁并发控制协议。对于叶节点操作,采用日志结构的插入和原地更新/删除,结合CAS原语,支持无锁访问。(2)减少PM开销,将叶节点的元数据和键值对解耦,元数据与内部节点一起存储在DRAM中,键值层存储在PM。提出了缓存持久分配器,利用持久CPU缓存来吸收分配、释放和日志记录过程中的大部分PM写入。采用日志结构的插入和原地更新来提高局部性。