PMFS文件系统

  • 1. 背景(Background)
  • 2. 动机(Motivation)
  • 2.1 为什么设计NVM文件系统
  • 2.2 NVM设备为文件系统设计带来的挑战
  • 2.3 贡献
  • 3. PMFS设计与实现(Design & Implementation)
  • 3.1 系统概貌
  • 3.2 Mmap I/O优化
  • 3.3 一致性设计
  • 3.3.1 In-Place更新
  • 3.3.2 元数据一致性
  • 3.3.3 页面分配器一致性
  • 3.3.4 崩溃一致性(PMFS恢复)
  • 3.3.5 数据一致性
  • 3.4 写入保护
  • 3.5 测试和验证
  • 4. 评估(Evaluation)
  • 4.1 实验设置
  • 4.2 基于文件访问的测试
  • 4.2.1 FIO
  • 4.2.2 File Utilities
  • 4.2.3 一致性性能测试
  • 4.2.4 Filebench测试
  • 4.3 Mmap I/O测试
  • 4.3.1 FIO
  • 4.3.2 Neo4j图数据库
  • 4.4 写入保护测试
  • 总结
  • Features

拖了好久了,终于把这篇文章看了,假期还会读几篇文章,大家多多点赞、评论+关注,这样才有更新的动力呀!

1. 背景(Background)

NVM(Non-Volatile Memory)技术的诞生,进一步缓解了存储器与CPU速度不匹配的问题。并对如今软件、硬件的系统设计产生了极大的影响。

PMFS设计的目的便是通过洞悉NVM设备性能特性,设计高效的NVM文件系统,从而使得应用程序能够高效使用NVM设备

NVM主要具有如下三个特性:

  • 可字节寻址
  • 存储持久化
  • 低延时、高带宽

Table 1给出了当时的各存储设备特性,其中,NAND Flash是Flash设备,RRAM(Resistent-RAM,阻抗内存)PCM(Phase Change Memory,相变存储器) 是NVM设备。

镜像里 npm执行太慢 镜像文件pmf_Linux

注意:NVM的设备的延时和带宽在数量级上比较接近DRAM,但仍然差距1个数量级

2. 动机(Motivation)

2.1 为什么设计NVM文件系统

传统的操作系统将易失内存管理(例:Virtual Memory Managment,VMM管理)存储设备管理(例:文件系统或块设备驱动) 分开。

NVM既具有内存的特性(可字节寻址),又具有存储设备的特性(可持久化)。因此,系统软件可依赖如下方式来管理NVM设备:

  • 扩展VMM,用内存方法来管理NVM;
  • 实现块设备兼容层,使得传统块设备文件系统(例如:EXT4文件系统)可以直接用于管理NVM;
  • 针对NVM特性设计文件系统,绕过块设备层;

PMFS一文采用第三种方式,原因如下:

  • 提供传统应用支持。大多数应用依赖于文件系统接口,故设计实现NVM文件系统;
  • 提供更高效的文件系统。 PMFS绕过块设备层,充分利用NVM的字节访问特性来发挥NVM的性能;
  • 提供优化的mmap I/O。 传统文件系统在mmap时,将页面拷贝到DRAM中,PMFS直接将NVM映射到用户空间,避免拷贝。

由以上种种原因,作者们决定设计针对NVM特性的文件系统。

2.2 NVM设备为文件系统设计带来的挑战

本节介绍PMFS设计的动机,通俗来讲:为什么PMFS要这么设计?

系统设计的动机非常重要,在任何工作中,动机一旦不成立,就没有做这个工作的必要了。

个人认为,动机也是一篇工作中最难的部分,它的好坏直接决定整个故事能否讲得圆满,能否逻辑闭环,因此,动机是整篇文章的灵魂。

动机常常伴随着一系列挑战,PMFS在文中提出如下挑战:

  • NVM写入顺序和持久能力。PMFS将NVM视为一个具有回写缓存的内存。即,向NVM的写入不能保证持久性以及顺序性。为了解决这个问题,文章提出pm_wbarrier硬件原语用于保证写入的持久性。
  • 有效避免恶意写入(Stray Write)。PMFS将NVM映射到内核空间,此时,并不能保证这段空间不会被其他BUG内核程序给污染(Corruption)。为了解决这个问题,有一种思路是将所有NVM页面标记为read only,然后写时将其变为writeable,但这样会降低快表(TLB)的效率。于是,鉴于性能和简便性考虑,PMFS利用处理器的写保护控制手段,采用write windows方法。
  • 一致性验证方法。基于NVM的一致性验证方法较为复杂,PMFS采用YAT(该团队之前的工作)来进行验证。
  • mmap接口还是过于底层。关于这一点,PMFS的设想是基于PMFS实现PMLib来封装mmap(可能类似于PMDK?),这一点留到以后去完成。

2.3 贡献

本文主要贡献如下:

  • NVM系统新架构:pm_wbarrier硬件原语,用于保证NVM写入的持久;
  • PMFS文件系统的设计与实现:
  • 细粒度一致性保证;
  • mmap优化;
  • 低开销避免恶意写入(Stray Write);
  • 详细的性能评估

3. PMFS设计与实现(Design & Implementation)

3.1 系统概貌

  • PMFS地位
    PMFS向下管理NVM(文中称为Persistent Memory,PM)硬件设备,并向上应用层提供POSIX文件系统接口及直接NVM页面映射的mmap方法。
    PMLibmmap封装起来,以供应用更方便地访问。

镜像里 npm执行太慢 镜像文件pmf_NVM_02

  • 文件系统布局
  • Super Block
    双Super Block冗余设计,降低系统崩溃后无法恢复风险。
  • PMFS-Log
    元数据项日志。
  • 介质上索引
    B-树结构组织访问,因为B树适合索引大量稀疏数据节点。

镜像里 npm执行太慢 镜像文件pmf_NVM_03

  • 文件系统页面分配器
  • 基于页面的分配器,支持4KB、2MB以及1GB页面。对于元数据,PMFS使用4KB页面;而对于文件数据,PMFS可以使用4KB、2MB以及1GB页面。
  • 分配器的设计与操作系统虚拟内存分配器设计类似,但是提供了一致性和持久性保证。
  • 该分配器仍然有碎片化问题,这留待以后去研究。

可以看到,整个PMFS的设计并不复杂,比较中规中矩。其较以往的文件系统的主要优势:与以往NVM文件系统(BPFS)相比,PMFS胜在细粒度元数据日志;与传统块设备文件系统(Ext 4)相比,PMFS胜在无需经过页面缓存(Page Caching)。

3.2 Mmap I/O优化

  • PMFS将NVM上的数据直接映射到用户空间,于是用户可以直接访问NVM;
  • PMFS的mmap将尽可能选择大页进行映射。利用大页进行映射的好处是:
  • 减少Page Table内存占用开销;
  • 更高效的TLS访问以及更少的Page Fault;
  • 更短的Page Table Walk;

当然,这也有一定的弊端。比如,如果应用程序不需要大页映射,那么就会造成严重的内部碎片(例如:分配1G的内存页面,但是程序只用其中100MB,那么就有900MB的内部碎片)。为了优雅地解决这个问题,PMFS采用HINTS的思想——例如,如果一个程序想让文件增长到10GB,它便可以利用fallocate(10G)ftrucate(10G)来告知PMFS,从而PMFS便选择用1GB的页面而非4KB的页面来表示一个文件数据

3.3 一致性设计

最为核心的是细粒度日志设计。传统的保证一致性方法有三种:CoW(写时复制)、Jounaling(日志)、Log-structured(日志结构)。

考虑到CoW文件系统Log-structure文件系统分别以Block或Segment粒度进行,这会带来不可忽视的写放大。而Jounaling机制又会带来Double Wirte问题,这不适于数据量大于4KB的写入。

综上考虑,PMFS采用Jounaling和处理器自带的原子写操作)保护元数据一致性(通常是小数据),采用CoW保护数据一致性。(在NOVA一文中,作者说PMFS并没有保证数据的一致性,这里是否说错了呢?或者是PMFS的开源代码中还未实现CoW机制)。

3.3.1 In-Place更新

传统的NVM系统设计一般利用的是8字节原子写,PMFS根据硬件特性,采用了多种多样的原子写机制:

  • 8字节原子写。处理器本就支持。
  • 16字节原子写。利用cmpxchg 16b指令,加上LOCK前缀。
  • 64字节(Cacheline对齐)原子写。如果处理器支持Restricted Transcational Memory(RTM),那就可以,否则采用细粒度日志。
3.3.2 元数据一致性
  • 日志结构: 利用一个循环Buffer作为日志,即PMFS-Log。日志包含headtail指针。
  • 日志项: 每个日志项为64字节,如图4(b)所示。
  • 事务动作:
  • 开始事务: PMFS首先原子增长日志tail,在日志中写入所有即将被改变的元数据,最后,使用flushpm_wbarrier保证这些写入成功持久化到NVM上。
  • 结束事务: PMFS追加commit标记,并提交事务。这里要注意的是,commit标记不一定要使用pm_wbarrier。commit标记的持久化被延迟到下一次事务开始,或是被后台线程标记。
  • 垃圾回收: 垃圾回收依靠后台线程log_cleaner执行,它会首先发送pm_wbarrier,保证所有日志写入均已持久化,再原子地更新日志的head指针以清除日志。

镜像里 npm执行太慢 镜像文件pmf_镜像里 npm执行太慢_04

3.3.3 页面分配器一致性

PMFS将页面分配器布局在DRAM中,于是不必使用日志来保证它的一致性,从而降低了维护页面分配器一致性的开销。

在正常卸载时,PMFS将页面分配器存储在一个预留的Inode中,以便下次恢复快速构建页面分配器的状态。

3.3.4 崩溃一致性(PMFS恢复)

系统崩溃后,PMFS首先通过Undo PMFS-Log来完成系统一致性的恢复。其次,它扫描所有B-树来重建页面分配器。

3.3.5 数据一致性

通过CoW(写时复制)保证。数据的写入依靠NT Store指令(Non-temporal Store)。

3.4 写入保护

PMFS详细地描述了对于NVM设备的写入保护方法,如表2(X-Y,即行-列,意味着避免Y影响X,原文是X from Y)所示:

镜像里 npm执行太慢 镜像文件pmf_Linux_05

其中,“用户-用户态”的写入保护依赖进程间隔离;“用户-内核态”的写入保护依赖Supervisor Mode Access Prevention(SMAP,管理模式访问保护)特性;“内核-用户态”的写入保护依赖特权级别

“内核-内核态”的保护极具挑战性,PMFS认为使用write windows方法(处理器的写入保护控制,CR0.WP)来实现写入保护:将整个NVM设备映射为只读,要写的时候开个写入窗口,写完后立马关闭窗口。如下图所示(其中,ring0代表Supervisor-mode,即内核模式监督模式):

镜像里 npm执行太慢 镜像文件pmf_file system_06

图5左上“CR0.WP in x86”代表内核写入逻辑:如果此时为内核态,且CR0.WP = 0,那么向页面P的写入是允许的,否则造成General Protection Fault

需要额外注意的是,允许写入(disable_write_protection())过程是不允许中断的,从而保证此次写入只有当前调用disable_write_protection()的PMFS在写。

3.5 测试和验证

文章通过Yat方法进行一致性检测与文件系统验证,并且设计fsck工具来进行完整性校验。最终得出结论:Yat适于检测基于NVM的系统的一致性。且表明PMFS的一致性经受住了考验

4. 评估(Evaluation)

4.1 实验设置

  • 实验平台: PM Emulator Platform(PMEP)
  • PMDB: 为了保证实验的公平性,PMFS设计实现了PMBD,一个针对NVM优化的块设备驱动。传统的NVM块设备驱动不能区分NVM和DRAM,并且会受到操作系统分页机制的影响,而PMBD解决了这一问题,并且利用NT Storepm_wbarrier进行数据块的写入。

4.2 基于文件访问的测试

4.2.1 FIO

实验对象: PMFS、EXT4和EXT2(块设备文件系统代表)。这里并未与BPFS做对比,有点缺乏Convince。

实验设计: 单线程写入64GB文件,横坐标为I/O大小,纵坐标为带宽吞吐。

实验结果:

镜像里 npm执行太慢 镜像文件pmf_NVM_07

实验解释:

  • PMFS在读写方面都更胜传统块设备文件系统(EXT4)一筹,主要得益于其避免了Page Caching的Double Copy;
  • 可以看到,当写入的大小大于是16KB时,写入性能降低。这主要是因为NT Store指令。虽然NT Store可以绕过CPU缓存,但还是需要检查CPU Cache来保证缓存一致性,从而引入额外开销。
4.2.2 File Utilities

实验对象: PMFS、EXT4和EXT2(块设备文件系统代表)。这里并未与BPFS做对比,有点缺乏Convince。

实验设计: 使用Linux Kernel Sources压缩包作为测试对象,并使用如下工具:

  • cp:拷贝压缩包至相同目录下;
  • untar:解压压缩包;
  • find:在解压后的目录中找不存在的文件
  • grep:在解压后的目录中找不存在的模式串
  • cp -r / rm -r:拷贝整个解压后的目录 / 删除拷贝出来的目录;

实验结果:

镜像里 npm执行太慢 镜像文件pmf_镜像里 npm执行太慢_08

实验解释:

不多提,PMFS在各种测试下都表现优异,特别是在写入较多(Write Intensive)的场景下,这在很大程度上是因为避免了Double Copy。但是在untar过程中,PMFS提升不是很足,这是因为untar仅涉及单线程顺序写,且对延时不敏感(对这个解释我不是很满意,根据4.2.1节中的分析,个人认为很大可能是untar涉及的I/O单元较小)

PMFS在rm -r中效率低于EXT2,这是因为EXT2没有Journal操作,避免了额外的日志写入开销。

4.2.3 一致性性能测试

实验对象: PMFS、BPFS、EXT4

实验设计与结果:

  • 首先,PMFS对In-Place原子更新与细粒度日志做了对比,发现In-Place原子更新性能更佳,提升大概为1.8X
  • 其次,PMFS对细粒度日志做评估。BPFS采用CoW进行元数据保护,EXT4采用粗粒度日志(每个日志项4KB)对元数据进行保护,因此,PMFS需要额外引入的日志写入远远小于BPFS与EXT4
4.2.4 Filebench测试

实验对象: PMFS、EXT4、EXT2

实验设计: 使用Filebench对负载进行模拟

实验结果:

镜像里 npm执行太慢 镜像文件pmf_NVM_09

实验解释:

  • 图8(a):图a是IOPS的对比,可以看到,PMFS在各种环境下性能都具优势。但是OLTP负载下提升较低,这是因为OLTP访问文件系统频率较低
  • 图8(b):对于OLTP这种访问频率较低的工作负载,增大NVM的延时使得PMFS性能基本不受到影响,而其他工作负载则不然;
  • 图8(C):pm_wbarrier对性能的影响蛮大,因此需要合理使用;(这里很有意思的是,作者图纵坐标采用的是Normalized Performance,很有可能是持久化元数据影响并没有这么大,为了放大这种差距,才使用标准化指标。那么,为什么非要强调这一点呢?其实主要是为前面的事务commit设计做解释:为什么要减少pm_wbarrier使用?是因为pm_wbarrier会对性能造成巨大影响,如果这个影响不巨大,那么就没有减少的必要了……实际上个人认为多半是没必要的,因为元数据相比数据块而言实在太小,这些原语的延时基本会被数据块的写入隐藏,导致其对性能的影响微乎其微,当然,这是个人见解);

4.3 Mmap I/O测试

4.3.1 FIO

实验对象: PMFS、EXT4、EXT2

实验设计: 使用不同的页面大小,利用fallocate创建文件进行测试。其中,PMFS-D代表使用4KB页面;PMFS-P代表使用4KB页面,并且在mmap的时候使用MAP_POPULATE选项,避免缺页影响;PMFS-L代表使用1GB页面。

实验结果:

镜像里 npm执行太慢 镜像文件pmf_PM_10

实验解释:

  • PMFS的mmap直接将NVM页面映射到用户空间,避免了额外的拷贝,因此性能远远高于EXT4和EXT2;
  • 大页mmap能够有效提升PMFS的mmap性能;
  • 大页mmap能够有效缩短Page Table Walk的时间减少Page Fault以及增大TLB命中率(图9 (c)),从而使得开销都只在用户态;
4.3.2 Neo4j图数据库

实验对象: PMFS、EXT4、EXT2

实验设计: 利用Wikipedia上的测试方法进行测试

实验结果:

镜像里 npm执行太慢 镜像文件pmf_PM_11

实验解释:

  • 插入性能与删除性能提升不太大,主要原因是基于PMFS mmap的Neo4j的插入与删除都是通过直接访问NVM完成的。这使得插入与删除性能主要受到NVM的写入影响;
  • 读取性能提升非常大,主要是PMFS的mmap避免了拷贝,而是把NVM页直接映射到用户空间中;这也意味着未来的NVM软件设计都可以采用mmap读的方式;

4.4 写入保护测试

实验对象: PMFS采用PGT-WP(更新页表的权限)、CR0-WP(写窗口,即本文的方法)以及不要写保护;

实验设计: 利用FIO和Filebench进行测试;

实验结果:

镜像里 npm执行太慢 镜像文件pmf_file system_12

实验解释:

  • 可以看到,CR0-WP对于总体性能的影响微乎其微,适于写入保护;
  • CR0-WP在Fileserver负载下一定的下降,这是因为对CR0.WP的修改是串行的,这对于多线程多写入负载场景会造成一定的性能下降。
  • PGT-WP在写入较多的负载下性能会有巨大的下降(例如Fileserver);

总结

本文主要着眼于NVM带来的新型架构,并针对该架构进行大量一致性、持久化设计工作,以及性能优化工作。

我们回过头来看PMFS,其实主要优势在于:

  • 绕过块设备层,直接访问NVM;
  • 多样化原子写、细粒度日志以及CoW,保证系统一致性;
  • mmap时,直接将NVM页面映射到用户空间以及隐式大页分配;
  • 基于处理器CR0.WP的轻量级写入保护机制;

事实上,PMFS并没有在文件系统布局、索引或数据组织上下很大的功夫,主要为基于NVM的系统设计提供思想:NVM文件系统的本质是直接访问NVM低一致性开销以及优化mmap

这也难怪本文标题不是PMFS,而是”System Software for Persistent Memory“。

Features

  • Redundent Super Block (Double Super Block).
  • Various In-Place Atomic Update. 8Bytes, 16Bytes and even 64 Bytes.
  • Fine-grained Logging. Comparing to CoW Journal, it brings low consistency overheads.
  • OS VMM page allocator in DRAM.
  • B-Tree In-NVM Indexing.
  • Mmap directly within transparently large page (1 GB).
  • Allocate page hints from syscall (fallocateand ftruncate).
  • Write window protection. Low overheads stray write protection by leveraging the processor’s ability.
  • Validated by Yat.