问题
持久内存编程库的崩溃一致性要求程序员使用复杂的事务和手动注释。而故障原子msync()(FAMS)接口要简单得多,因为它透明地跟踪更新,并确保在调用msync() 的故障原子变体时修改的数据在原子上是持久的。然而,FAMS有几个缺点,比如msync() 的开销和页面级脏数据跟踪的写入放大。
挑战
msync()接口并不能保证崩溃一致性。一个常见解决方法是实现预写日志[6-8](WAL),允许在故障后从不一致的状态中恢复。但是,通过WAL实现崩溃一致性要求应用程序多次调用msync()/fsync(),以确保应用程序数据在崩溃后始终可恢复到一致状态。
FAMS优化了崩溃一致性,推迟对备份介质的更新,直到应用程序调用msync(),然后利用文件系统日志以原子方式应用它们。FAMS是在内核中实现的,依赖于操作系统来跟踪页面缓存中的脏数据。但有几个限制:
-
msync()上的写放大:操作系统以页面粒度跟踪脏数据,即使是单字节更新也需要整页写回。使用2 MiB大页面来降低TLB压力会加剧此问题。
-
脏页跟踪开销:FAMS依靠页表来跟踪脏页,每个msync()都需要进行昂贵的页表扫描,以找到要写入备份介质的脏页。由于操作系统负责维护TLB的一致性,内核必须在清除访问和脏位后执行TLB刷新,这会给每个msync()调用增加大量开销。
-
上下文切换开销:在内核中实现崩溃一致性(例如,FAMS)会为每个msync()调用增加上下文切换开销,这加剧了当前实现中跟踪脏页的高开销。
本文方法
本文提出了Snapshot,一种高效的FAMS用户空间实现。
-
使用基于编译器的注释,透明的跟踪用户空间中的更新,避免了上下文切换开销,并在调用msync() 时将其与可字节寻址的备份存储副本同步。
-
通过在DRAM中保留应用程序数据的副本,降低访问延迟。
-
与POSIX msync() 系统调用不同,仅在调用msync() 时自动跟踪和同步更改,从而提供了崩溃一致性保证。
在模拟的CXL内存语义SSD上,Snapshot在除一个YCSB工作负载外的所有工作负载上都比PMDK高出10.9倍。此外,Kyoto Cabinet提交使用快照的性能比其内置的基于msync()的崩溃一致性机制快8.0倍。
实验
实验环境:基于NUMA的评估平台,使用共享内存实现了DRAM缓存,并使用SPDK在用户空间中实现了来自真实SSD的服务缓存缺失。目标应用程序和模拟SSD被固定到不同的插槽,以模拟CXL链路。
数据集:YCSB
实验对比:加速比、执行时间
总结
针对故障原子性msync()的优化,现有方法存在:写放大;脏页跟踪开销;上下文切换开销。本文提出了Snapshot:(1)使用基于编译器的注释,透明的跟踪用户空间中的更新,避免了上下文切换开销,并在调用msync() 时将其与可字节寻址的备份存储副本同步。(2)在DRAM中保留应用程序数据的副本,降低访问延迟。(3)仅在调用msync() 时自动跟踪和同步更改,从而提供了崩溃一致性保证。