在上篇的 NVDIMM介绍中,我们讲解了NVDIMM几种硬件上的实现方式,以及为了支持和优化性能所做的硬件上的改变。
接下来让我们来讨论一下为了充分发挥NVDIMM的性能,软件方面做了哪些支持。有些人可能会有疑问,为什么用起来这么麻烦?既然是持久性内存,不是应该关机什么样, 开机什么样,就可以了吗?
其实目前来看,这种想法还不会变为现实。因为除了DRAM是易失性的,比如 cache,寄存器这种也是易失性的。仅仅把内存做成持久性的也不能达成这样的目的。
另一个问题是, memory leak。如果发生了内存泄漏,重启一下就好了。那如果是持久性内存的泄漏呢?这也是一个很棘手的问题。Pmem有些方面类似于内存,也有些方面类似于存储。但是,通常上我们不会认为Pmem能够替代内存或存储。其实,可以把它看作是一种补充,填补了内存和存储之间巨大的差异。
SPDK 在 17.10 中开始引入对于Pmem的支持。Pmem在SPDK的bdev层暴露为一个块设备,使用快设备接口和上层进行通信。
如下图所示:
从图中我们可以看到libpmemblk 把块操作转换成了字节操作。它是怎么做到的呢?在介绍libpmemblk 和 它背后的PMDK之前, 我们了解一下基础知识。
mmap和DAX
首先,我们来看传统的I/O方式, 即缓存I/O (Buffered I/O). 大多数操作系统默认的IO操作方式都是缓存IO。该机制使IO数据缓存在操作系统的page cache 中, 也就是说, 数据会被先拷贝到操作系统的内核空间的缓冲区中,然后才会从内核空间的缓冲区拷贝到指定的用户地址空间。
在Linux 中, 这种访问文件的方式就是通过read/write系统调用来实现,如上图。接下来, 我们比较一下内存映射IO mmap()。
接下来, 我们比较一下内存映射IO mmap()。
通过mmap获得了对应文件的一个指针,然后就像操作内存一样进行赋值或者做memcpy/strcpy. 这种我们称之为load/store操作(这种操作一般需要msync、fsync来落盘)。
mmap因为建立了文件到用户空间的映射关系,可以看作是把文件直接拷贝到用户空间,减少了一次数据拷贝。但是mmap依然需要依靠page cache。
讲完了mmap,那么DAX是什么呢?DAX即direct access,这个特性是基于mmap的。而DAX的区别在于完全不需要page cache,直接对存储设备访问,所以它就是为了NVDIMM而生的。应用对于mmap的文件操作,是直接同步到NVDIMM上的。DAX目前在XFS, EXT4, Windows的 NTFS 上都已经支持。需要注意的是, 使用这个模式,要对应用程序或者文件系统进行修改。
NVM Programming Model
NVM Programming Model 大致定义了三种使用方式。
最左边Management 主要是通过driver提供的API对NVDIMM进行管理, 比如查看容量信息、健康状态、固件版本、固件升级、模式配置等等。
中间,作为存储快设备使用, 使用支持NVDIMM driver 的文件系统和内核, 应用程序不用做任何修改,通过标准文件接口访问NVDIMM。
第三种, 基于文件系统的DAX特性,通过load/store操作,不需要page cache,同步落盘,没有系统调用, 没有中断。这也是NVM Programming Model 的核心, 能够充分释放NVDIMM的性能优势。但它的缺点在于,应用程序可能需要做一下改变。
PMDK
libpmemblk 实现了一个驻留在pmem中的同样大小的块的数组。里面每个块对于突然掉电,程序崩溃等情况依然保持原子事务性。
libpmemblk是基于libpmem库的,libpmem是PMDK中提供的一个更底层的库, 尤其是对于flush的支持。它能够追踪每次对pmem的store操作,并保证数据落盘为持久性数据。
除此以外, PMDK 还提供了其他编程库, 比如libpmemobj,libpmemlog,libvmmalloc 等。
至此,对于NVDIMM硬件和软件上的不同, 大家都有了一个大致的认识。
NVIDMM分类
NVIDMM-N:memory mapped DRAM,提供字符访问接口,在三种产品中性能最好,容量最小。
NVDIMM-F:memory mapped Flush,只提供块设备接口。Nand Flush直接链接到Memory controller channel。
NVIDMM-P:Under Development,提供块设备和字符设备访问接口。
01特性
NVDIMM-N:NVDIMM-N既可以用作缓存,又可以作为块存储设备来用。典型代表是类似intel 的AEP。
NVIDMM-F:不同于NVIDMM-N主要用作缓存,NVIDMM-F主要用作存储。可以用来快速构建高密度的内存池存储池。
02构建基于NVDMM的文件系统
门为PMEM设计的文件系统是NOVA Filesystem,感兴趣的读者可以参考NOVA的github。
ZUFS作为来自于NetApp的一个项目,ZUFS的全称是Zero-copy User Filesystem。声称是实现了完全的zero-copy,甚至文件系统的metadata都是zero-copy的。ZUFS主要是为了PMEM设计,但是也可以支持传统的磁盘设备,相当于是FUSE的zero-copy版本,是对FUSE的性能的提升。
03在用作DRAM的模式下
支持全系统掉电保护, 不少场景下为了防止异常掉电丢数据的commit and flush 的两阶段提交方法,可以省略成一阶段的commit on write 的方法
3.1 为DRAM和SSD物理之间提供了一个新的存储层
3.2 由于用作DRAM的时候,其访问速度比SSD可能有1~3个数量级的提升,在一些文件系统中可以去掉对page cach的依赖,这样反而更能控制上层业务的平均延时和服务稳定性。
DAX 顾名思义,DAX就是Direct Access, bypass page cache。读写直接操作PMEM上的数据,文件系统需要在mount 的时候,加入 "-o dax"参数。DAX极大地提高了文件系统在PMEM设备上的性能,但是还有一些问题没有解决,比如:
文件系统的metadata还是需要使用page cache或buffer cache。
"-o dax" mount option是对整个文件系统的,不能做更细粒度的控制。
3.3 没有一个API来告诉应用访问的文件是不是可以DAX访问的。
04NVDIMM在Linux下的实现
持久内存是一种新型的计算机储存,其速度接近动态 RAM (DRAM),但同时具备 RAM 的按字节寻址能力以及固态硬盘 (SSD) 的性能;与传统的 RAM 一样,持久内存直接安装在主板上的内存插槽中。因此,它的物理外形规格与 RAM 相同,以DIMM的形式提供。这些内存称为NVDIMM:非易失性双列直插式内存模块。
不过与 RAM 不同,持久内存在多个方面类似于基于闪存的 SSD。后两者采用固态内存电路的形式,但除此之外,两者都提供非易失性储存:系统断电或者重启动后,内存中的内容会得到保留。使用这两种媒体时,写入数据的速度比读取数据要慢;两者都支持有限的重新写入周期数。最后,与 SSD 一样,如果在特定的应用方案中更适合对持久内存进行扇区级别的访问,则也可以这样做。
不同的型号使用不同形式的电子储存媒体,例如 Intel 3D XPoint,或者将 NAND 闪存与 DRAM 结合使用。另外,行业正在开发新形式的非易失性 RAM。这意味着,不同的供应商和 NVDIMM 型号会提供不同的性能和持久性特征。
由于涉及的储存技术处于早期开发阶段,不同供应商的硬件可能会施加不同的限制。因此,以下叙述适用于一般性的场合。
持久内存的速度最多比 DRAM 要慢 10 倍,但比闪存要快大约 1000 倍。可在其中按字节重新写入数据,而不像在闪存中一样,需要擦除整个扇区,然后重新写入数据。尽管重新写入周期数有限,但大部分形式的持久内存可以应对数百万次重新写入,相比之下,闪存只能应对数千个周期。
这会产生两种重要后果:使用最新的技术无法运行仅包含持久内存的系统,因此无法实现完全非易失性的主内存,必须混合使用传统的 RAM 和 NVDIMM。操作系统和应用程序将在传统的 RAM 中执行,而 NVDIMM 可提供极速的补充性储存。
由于不同供应商的持久内存的性能特征不同,程序员可能需要考虑到特定服务器中 NVDIMM 的硬件规格,包括 NVDIMM 的数量,以及它们可以装入到哪些内存插槽。显然,这会对超级管理程序的使用、不同主机之间的软件迁移等造成影响。
如果想了解更多关于Linux的技术干货,请关注公众号【Linux架构师训练营】