摘要

将频繁(每毫秒)持久快照捕获到NVM的能力将支持许多引人注目的用例。不幸的是,现有的NVM快照技术存在持久性屏障暂停、对NVM的写入放大和/或缺乏超出单个套接字的可扩展性等问题。在本文中,我们介绍了NVOverlay,它是一种可扩展且高效的技术,用于将频繁的持久快照捕获到NVM,以便以后可以随机访问它们。NVOverlay使用一致快照跟踪有效地跟踪跨多socket并行系统的内存更改(自上一个快照以来),并使用多快照NVM映射将这些快照存储到NVM,同时避免过度的写入放大。我们的实验表明,与最先进的基于日志的快照技术相比,NVOverlay成功地隐藏了捕获这些快照的开销,同时将写入放大率降低了29%-47%。

1. 引言

字节寻址非易失性存储器(NVM)技术在如何利用持久性方面产生了许多令人激动的想法,我们在本文中的重点是专门讨论使用NVM支持频繁持久快照的好处和挑战。特别是,我们的目标是以每秒数百次(即毫秒级)的速率将进程的整个物理地址空间的持久快照捕获到NVM。

由频繁的持久快照启用的使用模型。有效地将频繁快照捕获到NVM的能力将实现一种持久的、多版本的内存系统,从而实现以下四种使用模式:(1)分布式云应用程序的时间旅行或记录和回放调试,在用户指定的事件(也称为“观察点”)上捕获快照,这些事件通常以突发方式发生(因为感兴趣的计算在分布式系统中流动);(2)实现持久和持久的数据结构;(3)细粒度系统备份和复制;(4)低延迟崩溃恢复。

关键挑战:跟踪内存更改并避免NVM写入放大。在支持高频持久快照以使其既高效又可扩展方面存在两个基本挑战。第一个挑战来自这样一个事实:当创建快照时,我们希望快速收集快照中必须存储的最小数据量。因此,第一个挑战是准确跟踪自上一次快照以来物理地址空间中发生的更改。跟踪这些“增量”是很困难的,因为我们希望在不降低正常执行速度的情况下捕获它们,并且因为我们希望在可伸缩共享地址空间系统(跨越多个套接字)上运行的整个并行应用程序中一致地捕获它们。一旦我们成功地确定了内存中应该是快照一部分的信息,第二个基本挑战就是通过有效地将快照写入NVM,使其持久化,以便以后可以随机访问(作为多个快照之一),同时避免NVM写入放大。

以前的工作。有许多软件和硬件建议将持久快照捕获到NVM。不幸的是,这些以前的设计同时存在重大的性能开销(由于持久性屏障暂停或NVM写入放大),缺乏对多套接字系统的可扩展性,和/或不支持随机访问多个以前的快照(这对于分布式调试使用模型很重要)。

基于软件的方法通常会由于持久性屏障而导致性能下降。此外,软件日志记录方法通过先将快照数据写入持久日志,然后再将其复制到NVM上的最终位置(可以通过地址随机访问),从而导致NVM写入放大。这种写入放大有效地将NVM带宽减半,并减少编程/擦除(P/E)可用次数。

硬件方案通过将正常执行与通过控制将缓存中的脏数据写回NVM的特殊硬件使快照持久化重叠来提高性能。虽然这些建议有效地消除了持久性障碍,但它们有两个主要缺点。首先,由于日志记录,它们通常会受到NVM写放大的影响(如上所述)。其次,它们通常不会扩展到多套接字系统,从而做出假设,例如单个套接字中包含的单片缓存层次结构,和/或引入不可缩放的结构,例如集中式映射结构或控制逻辑。

我们方法中的关键见解:NVOverlay。为了克服支持频繁持久快照方面的两个关键挑战,我们的NVOverlay设计基于两个关键见解。首先,为了解决以高效且可扩展的方式跟踪自最近快照以来对内存的更改这一难题,我们将多版本page overlay的新扩展与一组宽松的分布式epoch(使用Lamport时钟形式进行维护)相结合,创建了新的一致快照跟踪(CST)机制。其次,为了解决在将一组多个快照持久化到NVM时避免写入放大的难题,我们完全避免了日志记录,而是在我们的多快照NVM映射(MNM)机制中的NVM接口处使用一种形式的持久阴影映射。这两种机制的细节将分别在第四节和第五节中讨论,并在图1中说明。

我们的论文做出了以下贡献:

  • 我们提出并评估了NVOverlay,它支持对NVM进行高效且可扩展的高频快照,从而支持多种使用模型(包括分布式调试);
  • NVOverlay使用一致快照跟踪(CST)有效跟踪自上次快照以来对内存的更改,扩展到多插槽系统;
  • NVOverlay使用多快照NVM映射(MNM)来支持多个快照到NVM的持久性,同时避免写入放大;
  • 我们对NVOverlay的性能评估表明,它可以成功地隐藏创建频繁持久快照的大部分开销,同时将NVM写入放大率降低29%-47%。

2. 动机和相关工作

2.A 使用持久性屏障的故障原子性

为了实现NVM的故障原子性,今天的应用程序程序员一直在使用各种软件解决方案(因为尚未提供建议的硬件解决方案)。具体而言,这些基于软件的方法通常包括事务库、特殊数据结构、内存分配器和/或存储服务。所有这些软件方法都依赖持久性屏障来强制执行写顺序,这对原子性至关重要。例如,使用undo日志记录,在更新数据之前,日志条目被强制刷新到NVM。在Romulus(使用软件阴影映射)中,下一个事务只能在前一个事务的工作集变得持久后启动。

持久性屏障通常由一系列缓存行刷新指令(如clwb/clflush)和内存栅栏(如sfence)组成。但是,频繁使用持久性屏障会对性能产生负面影响,因为(1)处理刷新时管道会暂停,(2)可能会不必要地序列化多个屏障的执行。

2.B 执行与持久化重叠

为了消除软件持久性屏障,以前的工作建议添加专用硬件以在后台强制执行持久性。例如,硬件日志记录生成日志条目,并在后台协调数据写回,从而将持久化与执行重叠。这些持久性日志可由加载/存储单元、一致性控制器、缓存控制器或内存控制器管理。

虽然这些基于硬件的日志记录方法与软件方法相比运行时开销最小,但它们的主要缺点是NVM写放大。由于这些日志记录方法将日志数据和脏数据都写回NVM,因此它们通常会产生至少两个(在撤消+重做日志记录的情况下为三个)的写放大系数。从缓存层次结构到NVM的过多写回会浪费总线带宽,从而降低系统性能,并且还会缩短NVM设备的使用寿命(考虑到磨损前写入的数量有限)。

2.C 通过阴影减少写放大

为了避免硬件日志记录的NVM写入放大,另一种方法是硬件阴影分页,它将脏数据重新映射到另一个“阴影地址”,以避免覆盖当前一致映像。因为影子分页只对数据写入一次,所以它没有固有的数据写入放大。重新映射可由TLB或内存控制器执行。硬件阴影分页还可以在后台执行持久性操作,以帮助最小化运行时开销。

虽然我们相信硬件阴影分页通常是正确的,但现有的设计面临一些挑战:例如,工作集大小的限制、仅支持有限数量的快照以及不可重叠的映射表更新。NVOverlay是细粒度阴影模型的一种新方法,可以避免这些缺点,我们将在第II-E节中详细讨论。

2.D 可伸缩性

以前的持久快照方案遇到了许多可伸缩性挑战。首先,由于现代多核处理器具有非包容性的分布式LLC片,因此使用集中式LLC标记遍历器或控制逻辑的方案根本不起作用。第二,以前的大多数提案都假设一个全局同步的epoch;由于通信成本的增加,实现这一共识很难扩大规模。最后,由于来自所有组件的协调、同步写回,以前的设计往往会产生突发流量(特别是在频繁发生快照时)。随着系统规模的扩大,这些突发流量越来越可能通过使内存总线和NVM设备的带宽饱和而影响性能。

2.E 解决方案:NVOverlay

在较高级别上,NVOverlay采用了无障碍一致快照跟踪(CST)前端与重叠持久性以及查找粒度、阴影映射多快照NVM映射(MNM)后端的组合。这种组合消除了前端不必要的屏障暂停和后端的日志写入放大。

NVOverlay采用基于epoch的快照模型,其中执行被划分为不相交的间隔,称为“epoch”,这是快照的基本单元。NVOverlay将工作数据和快照数据分开维护。工作数据在NVM或DRAM中以普通方式维护。在不同时期生成的脏数据将作为单独的副本保存到NVM,这些副本可以独立访问。

前端和后端的设计都将可伸缩性作为主要设计目标之一。为了消除集中式epoch和控制逻辑,我们放宽了快照的一致性要求,允许快照在不一定符合系统中发生的任何实时状态的状态下拍摄,但在因果关系方面仍然保持一致,一致性协议对其进行了定义(见第III-C节)。为了实现这一点,我们将LLC上方的缓存层次划分为版本域(VD),并让每个域都保持自己的epoch。系统中的所有epoch计数器形成Lamport时钟[38],也以类似方式更新:当且仅当本地epoch观察到远程epoch生成的脏缓存行且i>j时,本地epoch计数器j更新为远程epoch计数器i。

VD生成的脏数据由版本标记的层次结构集体跟踪,其中每个逻辑缓存行都由一个额外的版本字段标记,该字段指示最后写入该行的epoch。NVOverlay保证在E版本停止活动后,版本E的脏行变为不可修改。这样,同一地址的多个实例在层次结构中共存,每个实例构成不同快照的一部分。版本一致性协议是对现有一致性协议的简单补充,它跟踪缓存中的版本并协调逐出以确保正确排序。同时,后端在接收到版本E的脏行时,将其插入到每epoch映射表中,该表支持随机的缓存行粒度访问。这些表还不断地合并到映射当前一致内存映像的持久全局主表中。合并期间不需要移动数据,因为只复制表项。

NVOverlay和其他类似设计之间的定性比较如表一所示。

3. NVOverlay洞察

3.A Page Overlays

page overlay最初是作为一种细粒度地址映射方案提出的,它允许虚拟地址以缓存行粒度映射到多个后备存储地址。层次结构中的每个缓存行都使用Overlay ID(OID)进行标记。使用不同OID标记的单个地址可以通过overlay内存控制器(OMC)映射到不同的物理位置,OMC充当位于缓存层次结构和主内存之间的内存控制器。

读者无需具备page overlay的先验知识即可理解NVOverlay。我们的工作基本上是独立的,同时与原始设计保持兼容。对原始page overlay设计感兴趣并与NVOverlay进行比较的读者,请阅读本文了解更多信息。

3.B 架构

图2描绘了系统架构。我们假设一个具有分布式末级缓存(LLC)的多核系统。LLC不需要包括在内,就像某些大型系统[80]的情况一样。包容性二级缓存可由少量内核共享。层次结构中的所有缓存标记都使用一个16位OID字段进行扩展,该字段存储上次更新该行的epoch ID。在图中,核心0、核心1和共享L2形成一个版本化域VD0,而其余两个核心和L2形成VD1。虽然只显示了四个内核和两个LLC片,但实际的系统可能要大得多,甚至是分布式的。

为简化设计,VD中的L1和L2缓存运行在相同的epoch。缓存控制器维护自己的cur-epoch寄存器,用于跟踪VD的当前epoch,这些epoch在VD内同步。由于VD相对较小,所以epoch同步是一个只引起本地通信的轻量级事件。

从缓存层次结构(不仅仅是LLC)中逐出的快照缓存行由集成到内存控制器中的OMC处理。OMC维护一系列映射表,将缓存行地址转换为NVM上的影子地址。如图所示,NVOverlay的控制逻辑可以分布在多个OMC上,以实现更好的可伸缩性,每个OMC负责自己的地址分区。请注意,应用程序可以使用DRAM或NVM或两者作为工作内存。

3.C 松弛epoch模型

从概念上讲,NVOverlay将单个VD的执行划分为由16位整数标识的epoch。为了便于讨论,我们首先假设只有一个VD存在。在每个epoch中,系统状态由存储指令更新。此类状态变化由NVOverlay的一致快照跟踪以增量方式捕获(见第四节),并作为快照保存到NVM。每个快照仅包含在该epoch内(而不是之前)所做的状态更改。VD中的处理器还在每个epoch结束时将其内部上下文转储到NVM,作为快照的一部分。

在崩溃恢复时,NVOverlay首先搜索最新的完全持久化的epoch E。然后通过合并E之前和期间的所有增量更改来重建一致的内存映像,时间与工作集大小成比例。

由于数据依赖性,当多个VD通过共享内存访问进行交互时,模型变得更加复杂。回想一下,与以前的方案不同,NVOverlay中的每个VD运行一个独立的epoch。例如,如果在epoch i中由VD X写入的缓存行在epoch j中由VD Y访问,那么如何观察数据相关性?

作为一种解决方案,在上述示例中,如果j < i,NVOverlay在观察到“来自未来”的数据时同步VD epoch。这类似于Lamport时钟捕获分布式系统中事件顺序的方式。作为权衡,NVOverlay拍摄的“松弛”快照在执行过程中的任何实时点都可能不是精确的内存映像。尽管如此,快照仍然正确地保留了系统进度,因为恢复后的映像在逻辑时间上是一致的。图3给出了一个示例。在此图中,捕获的快照仅分别反映时间t4、t7和t8中VD0、VD1和VD2的实时内存状态。然而,快照仍然是一致的,因为它捕获的本地VD状态与VD缓存间一致性暗示的因果顺序一致。

4. 连续快照跟踪(CST)

如第III-C节所述,一致性快照跟踪(CST)设计必须解决两个难题:状态变化的增量跟踪和时代的同步。在以下部分中,我们将详细讨论这两个主题。我们从单个VD内的操作开始,然后将讨论扩展到多个VD和缓存一致性。

我们假设基于目录的MESI是基线协议。该设计可以很容易地扩展到支持基于snoop的MESI,或其主流衍生产品,如MOESI或MESIF。我们还强调,NVOverlay不会修改基线协议。相反,只有少数额外的标记检查和逐出被添加到现有的一致性操作中。状态和转换保持不变。

4.A 版本访问协议

版本是其内容在epoch执行期间生成的缓存行。缓存行的版本号是其OID标记的值,在写入缓存行时,该标记被设置为VD的epoch号。通过网络发送的所有一致性消息还包含版本号RV(请求/响应版本),其含义将在下文中解释。

一个版本可以是干净的,也可以是脏的,具体取决于其一致性状态。例如,在MESI协议中,M状态行是脏的,而S和E状态是干净的。NVOverlay保持这种协议,即干净版本已经在NVM上持久化。因此,来自上一个epoch E’的脏版本在epoch E中是不可修改的,因为它可能是尚未持久化的E’快照状态的一部分。

版本访问协议的目标是确保仅访问最新版本,即使同一地址的多个版本可能在层次结构中共存。该协议还保证最终将层次结构中的所有版本逐出到NVM,而DRAM只保留最新版本作为工作副本。

接下来,我们将分别描述L1和L2缓存中的版本访问协议。

1)L1操作:

从处理器接收加载请求时,L1的行为与非overlay系统中完全相同。特别是,标记查找是在不检查OID标记的情况下执行的,这与比较地址+OID的原始page overlay查找协议不同。如果查找未命中,将在重试加载之前向L2发送GETS请求。否则,加载将在本地完成。

在接收到存储请求时,会像加载中一样执行标记查找。存储请求的RV设置为VD的cur-epoch。如果查找指示未命中,或者如果行未处于可写状态(E或M),缓存控制器将首先通过发送GETX来获取独占权限,然后重试存储。然后,控制器将行OID与RV进行比较。如果缓存行脏且OID等于RV,则存储在本地完成。否则,版本是不可修改的。在这种情况下,L1控制器将不可修改版本逐出到L2,而不会使行无效,并在调度逐出后执行就地存储(参见图4)。这种“存储逐出”在NVOverlay的设计中至关重要,因为它支持在层次结构中缓存多个版本,同时利用包容性二级缓存作为旧版本的临时缓冲区。行OID也更新为RV,以反映该行现在位于epoch RV的快照中的事实。

在缓存行逐出时,如果缓存行脏,则在L1的逐出缓冲区中调度PUTX请求,并将RV设置为行OID。是否处理干净的逐出取决于实现。由于缓存行逐出不在关键路径上,因此Store-Execution不会影响一级缓存访问延迟。

2)L2操作:

从L1接收GET或GETX时,L2像往常一样执行标记查找,如果块不存在或权限不足,则发出未命中信号。当请求的块在L2中时,它被读出并作为响应发送到L1,L1的RV被设置为行OID。

在从L1接收PUTX时,L2首先执行标记查找以读取行OID和一致性状态。如果缓存行脏,且OID < RV,那么L2逐出当前行以避免覆盖旧版本。这还保留了一个不变量,即同一地址上的L1版本不得小于L2版本。在这种情况下安排的驱逐不会使L1副本无效,因为包容性仍然有效。在所有情况下,L2都通过将数据和OID复制到缓存插槽中来完成请求。

在缓存行逐出时,如果行是脏版本,除了发送给LLC,L2控制器还通过一致性网络将版本发送给OMC,绕过LLC。注意,在非包容性LLC设计中,这种旁路网络已经存在,允许二级缓存直接写回预测为“dead”的缓存行。因此,我们的设计避免了添加专用数据路径,而只是利用了LLC旁路。请求的RV也设置为行OID。后端操作将在第五节中讨论。

3)外部失效和降级:实现外部失效和降级的主要挑战是L1和L2可能各自缓存脏版本。NVOverlay通过额外的逐出来解决这个问题,如下所示。

在接收到外部失效(DIR-GETX)或降级(DIR-GETS)时,二级控制器首先查询其自己的目录中的任何一级共享器。如果没有,L2为请求的版本安排逐出,从而在本地处理请求。行状态也分别设置为I或S。

如果存在L1共享,L2控制器首先将请求转发给它们。L1控制器只是在更改缓存行状态之前安排逐出。然后,L2控制器处理来自L1的逐出(如果有),并在本地处理请求。在这两种情况下,最新版本也会作为响应发送回目录,响应的RV设置为行OID。图5给出了一个示例。

我们的协议和基线之间的一个区别是,在这个过程中可能会生成两个逐出,而不是一个逐出,这将使LLC和OMC上的逐出流量加倍,因为从L2回写到LLC以满足转发一致性请求的每个版本都需要发送到OMC。当L1和L2都有缓存的脏版本,并且它们的OID不同时,就会发生这种情况,如图6所示。然而,仔细观察发现,通过利用两个简单的观察结果,可以避免多次驱逐。首先,如果L1和L2都有脏版本,则L2版本不需要逐出到LLC,因为它不构成当前内存映像(L1版本较新)。其次,如果请求是一个失效指令,并且当前VD拥有最新版本,那么该版本根本不需要发送到LLC目录(和OMC)以满足DIR-GETX请求。相反,启动缓存到缓存的传输以将缓存行直接发送到请求者缓存,从而减少写回通信量和一致性延迟(参见图6)。

4)LLC和DRAM操作:一旦一个版本离开VD,它就保证被持久化,即使一致性状态可能仍然指示脏。因此,LLC和DRAM不实施版本一致性协议,除非在写回时更新行OID。

为了在DRAM中维护每行OID,DRAM控制器可以为每个DRAM页面保留几个字,并以类似于ECC内存更新的方式更新OID和数据。事实上,16位OID只能存储在启用ECC的内存中的ECC库中。其他技术,如DRAM压缩[72],也可用于嵌入OID而无需额外成本。

通过在VDs之外保留行OID,我们可以避免丢失更新缓存行的最新epoch的轨迹。这对于“记住”数据依赖关系是必要的。

4.B 相关性驱动的epoch更新

1)VD一致性:VD内一致性保持不变,除了L1写回脏版本时,L2需要检查其本地版本,并可能安排逐出。图7和图8中给出了示例。

当缓存请求VD中不存在地址或权限不足时,请求变为inter-VD,由L2控制器转发到LLC目录。该目录进一步将请求(或失效、降级)转发给其他VD或LLC,与非NVOverlay缓存层次结构中完全相同。

2)增加epoch:当一个inter-VD请求收到响应时,响应的RV字段始终设置为行的OID。在收到这样的响应时,L2控制器将其cur-epoch寄存器与RV进行比较。如果RV较大,VD必须终止当前epoch,并前进到epoch RV。

为了推进epoch,L2控制器首先向VD中的所有核心发送信号,以暂停其管道。二级缓存控制器还停止响应外部一致性请求,并耗尽VD内请求队列(不可能出现死锁)。接下来,VD中的所有内核将其非特定上下文转储到NVM,并标记为cur-epoch。最后,所有缓存控制器中的cur-epoch寄存器更新为RV。

在实践中,为了避免VD之间出现大的epoch偏差,VD还可以在固定数量的指令或外部事件之后提前其本地epoch。在罕见的大纪元环绕事件中,请参考第IV-D节。

4.C 缓存标记遍历器

相关快照跟踪机制的最后一个组件是二级缓存标记遍历器,它是一个内置于缓存控制器中的硬件状态机。tag walker机会主义地运行,仅当未完成的请求不使用缓存标记时才扫描它们。每个VD都有自己的标签漫游器,如图2所示。

OID小于L2控制器当前epoch的脏版本将由标记遍历器写回NVM。除了向OMC发送数据和OID之外,写操作还将缓存行从M状态降级为E状态。当逐出时,E状态行将被丢弃,或者当从L1逐出同一地址上的脏行时,E状态行将被覆盖。不过,NVOverlay协议的正确性并不依赖于标记遍历器的进展。

4.D epoch环绕

从概念上讲,epoch数应该单调增加,因为它们代表了计算的进展。实际上,epoch数是用一个固定宽度的整数表示的,最终将环绕到零。

当系统接近环绕条件时,消除错误的最简单方法是在刷新缓存后,通过清除所有本地epoch和版本标记来重置系统范围的版本控制。第二种解决方案不强制重置,但将VD间的偏移限制为版本数字空间的一半。我们将epoch空间划分为两个大小相等的组,L和U。持久epoch检测位指示L中的epoch是否大于U中的epoch,或者相反(组内顺序不变)。OMC强制所有VD必须在同一组中运行epoch。每当VD第一次将其本地epoch从一个组推进到另一个组时,系统确保没有缓存行保留属于“新”组的标记,并翻转epoch检测位,基本上通过将当前较小组中的epoch号“移动”到当前较大组的前面来循环使用当前较小组中的epoch号。

4.D 讨论

协议兼容性:如开头所述,NVOverlay既不假设特定的一致性协议,也不修改一致性状态机。只要协议支持“所有权”的概念,它就可以扩展到支持NVOverlay。

一致性开销:NVOverlay的版本一致性协议只会产生更多的逐出,在大多数情况下,这超出了关键路径。这种逐出开销也存在于大多数后台持久性设计中。

减少NVM写入:如果一个地址在同一时间段内被L2频繁逐出或降级,将生成对NVM(而不是DRAM)的冗余写回。为此,我们建议在OMC中添加一个电池支持的写回缓存,以减少持久延迟和NVM写入。缓存实质上充当了一个持久的LLC,用于吸收版本逐出,这将在电源故障时刷新。

5. 多快照NVM映射(MNM)

5.A 总览

多快照NVM映射(MNM)机制跟踪从VDs中逐出的版本,该机制可根据请求检索。NVOverlay的MNM由OMC在DRAM和NVM中管理:可在恢复时重建的数据结构保留在易失性DRAM中,以获得更好的访问带宽并避免NVM争用。同时,版本作为overlay数据页在NVM中紧凑地维护。OMC使用一系列overlay映射表维护最近可恢复epoch的映像。正如我们将在下面看到的,这些表在后台不断更新,以合并从前端逐出的较新版本。图9描绘了MNM。

5.B 确定可恢复epoch

在NVOverlay中,只有在所有VD:(1)将其本地epoch推进到E之后,epoch E才会变得完全持久;(2)写回在E中生成的所有脏版本。此外,要使用epoch E进行恢复,E之前的所有epoch也必须是完全持久的。由于epoch不是全局同步的,因此必须以分布式方式确定可恢复epoch,如下所述。

每个标记遍历器都有一个本地寄存器min-ver,当标记遍历开始时,该寄存器被初始化为cur-epoch,并更新为遍历过程中遇到的最小版本OID。二级缓存控制器然后将min-ver发送到OMC,在OMC中维护系统中每个VD最近接收到的min-ver数组。在接收到消息时,OMC重新计算所有min-ver中的最小值作为可恢复的epoch Er。Er还被原子地写入NVM上的一个已知位置rec-epoch。

如果存在多个OMC,则每个OMC首先计算其本地Er,然后选择其中一个作为master,所有剩余OMC向其发送Er。主OMC在计算最小Er后保留最终结果。

5.C Overlay映射表(OMT)

分配给多快照NVM映射机制的NVM存储作为页面缓冲池进行维护,在系统启动时进行初始化,并由OMC硬件进行管理。OMC使用位图(见图9)跟踪页面的分配状态,存储开销可以忽略不计。索引不需要是持久的,可以在恢复时重建。

对于每个epoch E,OMC维护一个epoch可变映射表ME。映射表在DRAM中实现为四级基数树,类似于x86-64页表。表ME通过将版本的物理地址映射到NVM上的数据页来跟踪在epoch E中生成的版本。OMC将epoch作为单独的page overlay实例进行管理,每个实例都有一个映射表和一组不同的数据页面。在page overlay设计中,稀疏页面(只有几个版本的页面)被紧凑地存储在小于4KB的子页面中,以节省存储空间(参见第4.4节)。

当回写来自epoch E的版本时,OMC使用请求的RV查找MRV,然后使用物理地址作为密钥将该版本插入MRV。这个过程与操作系统填充页表的方式非常相似,只是NVOverlay使用48位物理地址作为表索引。

OMC还维护一个主映射表Mmaster,它存储epoch rec-epoch的覆盖映射。Mmaster是五级基数树(比每个epoch表多一级)。前四个级别与每个epoch表完全相同,最后一个级别由地址位6–11索引,用于缓存行粒度映射,如图10所示。Mmaster反映当前一致的内存映像,并且Mmaster的所有节点都在NVM上持久化。使用日志记录或持久缓冲区对Mmaster进行原子更新。每当OMC将rec-epoch从旧epoch Ei更新到新epoch Ej(j>i)时,OMC也会合并来自易失性表Mi+1、Mi+2、…、。。。,Mj,向Mmaster,推进一致内存镜像。更新过程只是扫描per-epoch表,对于每个版本V,将其物理地址和NVM地址插入Mmaster。在此过程中不复制任何数据页。OMC在后台执行表更新和合并,而不影响正常执行。

5.D 垃圾回收

一旦合并了表ME,从Mmaster中未映射的版本就会过时,这符合垃圾收集(GC)的条件。但是,我们不能立即回收它们的存储,因为版本是按照页面(或子页面,在稀疏页面的情况下,我们使用“页面”来表示以下两个页面)的粒度进行映射的,而在缓存行粒度中单独取消映射。

更新频率较低的缓存行将阻止对包含页进行GC,从而导致存储爆炸。当NVM存储耗尽时,OMC会向操作系统引发异常,如果可行,操作系统只需分配更多页面,并通知OMC物理地址范围。否则,如果操作系统认为向OMC分配更多页面是不可行的,例如,设备已满,或者存储消耗达到配额限制,则OMC需要执行版本压缩以释放一些空间。该算法在被调用时,将从仍然有Mmaster映射的版本的最早的epoch开始,并将这些版本复制到最新的epoch,就像这些地址是在当前epoch中写入的一样。然后可以安全地回收源页面。只要大多数地址在过去的几个时期内至少更新一次,产生的写放大就可以忽略不计。每个epoch表使用的DRAM页在合并到Mmaster后可以立即回收。

5.E 检索持久快照

回想一下,持久快照是以每epoch的方式存储在NVM上的,以便高效检索。根据场景的不同,可以使用每epoch映射表单独访问快照数据,也可以使用Mmaster仅访问最新快照。接下来我们将讨论几个使用快照的用例。

崩溃恢复:崩溃后,操作系统或固件首先将系统恢复到快照启动时的初始状态。然后,恢复过程通过扫描Mmaster并将所有版本读取到DRAM中相应的地址,从NVM加载一致的映像。完成后,该过程读取存储在NVM上的rec-epoch,并查找在rec-epoch结束时转储到NVM的处理器上下文。加载上下文后,系统恢复执行,就好像崩溃从未发生过一样。易失的OMC数据结构也会在恢复过程中重建。

远程复制:快照一旦持久化,就可以通过网络传输到远程备份计算机。收到快照后,远程计算机可以选择将增量更改作为重做日志进行重放,或者将其存档以备将来访问。然而,远程复制体系结构和原子性保证与我们的工作是正交的,在以前的工作中已经进行了非常彻底的研究。

调试/时间旅行读取:对于访问epoch E上的单个地址X,访问函数将查找最大的E’,E’≤ E、 其中ME’映射地址X。这种“直通”语义类似于在MVCC数据库中访问版本链的方式,这是必要的,因为快照是以增量方式保存的。

5.F 讨论

硬件成本:NVOverlay的硬件成本包括每缓存行16位OID标记字段和OMC逻辑。16位OID标签仅将片上SRAM存储总量最多增加3.2%。以前的提案中也存在类似的费用。替换算法和一致性状态机都没有改变,需要更少的验证成本。

OMC逻辑上充当内存控制器。它可以是专用CPU线程,如在软件管理的缓存中,也可以实现为硬接线逻辑,或者是嵌入式可编程微控制器芯片。

我们强调,NVOverlay的硬件添加,如OID标记线,在许多其他领域(如事务性内存)具有普遍的用途。此外,Page Overlay的广泛用户场景还允许在部署后探索潜在的许多新用例。

运行时DRAM开销:DRAM中的每个64字节行都标记有16位OID,导致的DRAM开销最多为3.2%。OID跟踪粒度也可以大于64字节。例如,OMC可能仅为每个4KB DRAM行保留16个OID标记,从而将标记开销降低到0.8%以下。在这种情况下,每个OID将由4条缓存行组成的“超级块”共享。只有当传入OID较大时,才会更新现有OID。

运行时NVM开销:NVM页面用于存储工作集和Mmaster。与以前的影子分页方案不同,在这种方案中,最坏情况下可能会有2倍的空间开销,NVOverlay允许用户通过设置空间开销阈值在写放大和存储之间进行权衡。如果正在使用的页面数超过此阈值,OMC将暂停添加新版本,并立即启动版本压缩以回收存储。

扩展到大型NVM阵列:在未来的NVM平台(其存储密度预计将高于DRAM)上,NVOverlay基于OMC的MNM设计也将扩展到大型NVM阵列。在这样的系统上,多个内存控制器可能共存,每个内存控制器负责为地址分区上的请求提供服务。每个OMC都为地址分区维护自己的overlay实例和Mmaster实例。选择一个OMC作为主机,它为所有VD维护min-ver阵列,并将其epoch更新发送给主机。

6. 实验框架

7. 实验结果

8. 其他相关工作

我们现在讨论一些超出第二节内容的其他相关工作。日志记录长期以来一直在传统的文件系统上实现,用于崩溃恢复。在操作提交之前,对其元数据的更改首先刷新到磁盘的日志区域,在崩溃后为了恢复,可以重放日志区域。日志记录与日志结构文件系统(LFS)相关,它将整个文件系统视为一个大型日志。在LFS下,数据和元数据没有固定的“主位置”:映射表用于定位给定逻辑地址的项,该映射表也记录到日志中。NVOverlay的后端(MNM)的工作原理与LFS类似,关键区别在于有多个日志对象(而不是一个),每个日志对象表示一个epoch的工作数据。

关于使用NVM改进文件系统,最早的NVM文件系统设计之一BPFS将整个文件系统视为B+树的森林。使用BPFS,每个更新操作都会通过写时拷贝(CoW)和原子指针摆动创建文件系统的新快照。类似地,Jacob描述了一种基于闪存的设计,该设计通过执行CoW的自定义FTL组合以及固件维护的映射表,将同一地址的映射条目“链接”在一起,从而跟踪快照。稍后可以检索这些快照以进行崩溃恢复。

与以前这些以文件系统崩溃恢复为目标的设计不同,本文中我们的目标是支持对基于DRAM的主内存中的完整地址空间进行高频快照,这涉及到几个额外的挑战。首先,支持崩溃恢复所需的快照频率比我们使用NVOverlay的目标要慢几个数量级,因此更容易避免性能瓶颈。其次,文件系统(和闪存)已经包含用于跟踪数据位置的显式元数据,而DRAM主内存则不是这样。我们NVOverlay设计的一个主要方面是,能够在保持全速运行的同时,将数据与DRAM和缓存中的独立多版本快照区分开来。第三,文件系统包含一个用于写操作的显式软件接口,这与CPU对主内存的写操作(由常规写指令以非常高的频率执行)不同。如前所述,NVOverlay使用一致快照跟踪(CST)和多快照NVM映射(MNM)来克服这些挑战。

9. 总结

在本文中,我们提出并评估了一种新的硬件技术(NVOverlay),用于将在大规模多处理器上运行的未修改并行应用程序的完整地址空间快照到NVM。通过利用page overlay来支持延迟持久化许多缓存驻留检查点,NVOverlay在许多基准上实现了比硬件阴影分页更好的性能。与硬件日志记录相比,NVOverlay显著减少了写入放大量(大约减少了两倍),因为它避免了向NVM写入日志和脏数据。当NVM带宽变得宝贵时(例如,在ART基准测试中),这种带宽节约会对性能产生显著影响。通过以高效且可扩展的方式支持快照,NVOverlay使崩溃恢复和基于检查点的调试中可能出现的频繁检查点对于大规模并行应用程序都切实可行。