28 持久内存 #
本章包含有关使用配备非易失性主内存的 SUSE Linux Enterprise 的附加信息。此类内存称为持久内存,由一个或多个 NVDIMM 构成。
28.1 简介 #
持久内存是一种新型的计算机储存,其速度接近动态 RAM (DRAM),但同时具备 RAM 的按字节寻址能力以及固态硬盘 (SSD) 的性能。
SUSE 目前支持在采用 AMD64/Intel 64 和 POWER 体系结构的计算机上,对 SUSE Linux Enterprise Server 使用持久性内存。
与传统的 RAM 一样,持久性内存直接安装在主板上的内存插槽中。因此,它的物理外形规格与 RAM 相同,以 DIMM 的形式提供。这些内存称为 NVDIMM:非易失性双列直插式内存模块。
不过,与 RAM 不同,持久内存在多个方面类似于基于闪存的 SSD。后两者采用固态内存电路的形式,但除此之外,两者都提供非易失性储存:系统断电或者重启动后,内存中的内容会得到保留。使用这两种媒体时,写入数据的速度比读取数据要慢;两者都支持有限的重新写入周期数。最后,与 SSD 一样,如果在特定的应用方案中更适合对持久内存进行扇区级别的访问,则也可以这样做。
不同的型号使用不同形式的电子储存媒体,例如 Intel 3D XPoint,或者将 NAND 闪存与 DRAM 结合使用。另外,行业正在开发新形式的非易失性 RAM。这意味着,不同的供应商和 NVDIMM 型号会提供不同的性能和持久性特征。
由于涉及的储存技术处于早期开发阶段,不同供应商的硬件可能会施加不同的限制。因此,以下叙述适用于一般性的场合。
持久内存的速度最多比 DRAM 要慢 10 倍,但比闪存要快大约 1000 倍。可在其中按字节重新写入数据,而不像在闪存中一样,需要擦除整个扇区,然后重新写入数据。最后,尽管重新写入周期数有限,但大部分形式的持久内存可以应对数百万次重新写入,相比之下,闪存只能应对数千个周期。
这会产生两种重要后果:
使用最新的技术无法运行仅包含持久内存的系统,因此无法实现完全非易失性的主内存。必须混合使用传统的 RAM 和 NVDIMM。操作系统和应用程序将在传统的 RAM 中执行,而 NVDIMM 可提供极速的补充性储存。
由于不同供应商的持久内存的性能特征不同,程序员可能需要考虑到特定服务器中 NVDIMM 的硬件规格,包括 NVDIMM 的数量,以及它们可以装入到哪些内存插槽。显然,这会对超级管理程序的使用、不同主机之间的软件迁移等造成影响。
ACPI 标准版本 6 中定义了此新型储存子系统。但是,libnvdimm
支持该标准颁布之前的 NVDIMM,可以相同的方式使用这些内存。
28.2 术语 #
- 区域
区域是持久内存中可划分为一个或多个名称空间的块。如果不事先将某个区域分配到名称空间,则您无法访问该区域的持久内存。
- 名称空间
非易失性储存的单个连续寻址范围,相当于 NVM Express SSD 的名称空间,或 SCSI 逻辑单元 (LUN)。名称空间作为单独的块设备显示在服务器的
/dev
目录中。根据所需的访问方法,名称空间可将多个 NVDIMM 中的储存合并成较大的卷,或者允许将这些储存分区成较小的卷。- 模式
每个名称空间还具有一种模式,该模式定义要为该名称空间启用哪些 NVDIMM 功能。同一父区域的同级名称空间始终具有相同的类型,但可将其配置为使用不同的模式。名称空间模式包括:
- devdax
设备 DAX 模式。创建单字符设备文件 (
/dev/daxX.Y
)。不需要创建文件系统。- fsdax
文件系统 DAX 模式。如果未指定其他模式,则使用默认值。创建块设备 (
/dev/pmemX [.Y]
),支持将 DAX 用于ext4
或XFS
。- 扇区
适用于不执行元数据校验和计算的传统文件系统。适用于小型引导卷。与其他操作系统兼容。
- raw
不包含卷标或元数据的内存磁盘。不支持 DAX。与其他操作系统兼容。
注意SUSE 不支持
raw
模式。无法在raw
名称空间中装入文件系统。
- 类型
每个名称空间和区域都有一种类型,该类型定义如何访问与该名称空间或区域关联的持久内存。名称空间的类型始终与其父区域的类型相同。有两种不同的类型:“持久内存”(可通过两种不同的方式进行配置),以及已弃用的“块模式”。
- 持久内存 (PMEM)
与 RAM 一样,PMEM 储存提供字节级别的访问。使用 PMEM 时,单个名称空间可以包含多个交错式的 NVDIMM,使这些 NVDIMM 都可用作单个设备。
可通过两种方式来配置 PMEM 名称空间。
- 将 PMEM 与 DAX 搭配使用
为 Direct Access (DAX) 配置 PMEM 名称空间后,访问内存时会绕过内核的页面超速缓存,并直接进入媒体。软件可以单独直接读取或写入该名称空间的每个字节。
- 带有块转换表 (BTT) 的 PMEM
与在传统的磁盘驱动器中一样,将按扇区访问配置为以 BTT 模式运行的 PMEM 名称空间,而不是像在 RAM 中一样采用按字节寻址的模式。某个转换表机制会将访问活动批处理成扇区大小的单元。
BTT 的优点在于提供数据保护:储存子系统会确保将每个扇区完全写入到基础媒体,如果某项写入操作出于某种原因而失败,则会取消注册该操作。因此,无法在给定的扇区中进行部分写入。
此外,对 BTT 名称空间的访问会由内核超速缓存。
缺点在于,BTT 名称空间不支持 DAX。
- 块模式 (BLK)
块模式储存将每个 NVDIMM 作为独立的设备进行寻址。此模式已遭弃用,且不再受支持。
除
devdax
名称空间以外,其他所有类型也必须使用文件系统格式化,如同使用传统的驱动器一样。SUSE Linux Enterprise Server 支持将ext2
、ext4
和XFS
文件系统用于此目的。- Direct Access (DAX)
DAX 允许将持久内存直接映射成进程的地址空间(例如,使用
mmap
系统调用进行映射)。- DIMM 物理地址 (DPA)
在单个 DIMM 的内存中充当偏移量的内存地址;即,在该 DIMM 中充当最低可寻址字节的从零开始的地址。
- 标签
储存在 NVDIMM 中的元数据,例如名称空间定义。可以使用 DSM 访问这些数据。
- 设备特定的方法 (DSM)
用于访问 NVDIMM 中的固件的 ACPI 方法。
28.3 使用案例 #
28.3.1 将 PMEM 与 DAX 搭配使用 #
必须注意,这种形式的内存访问不是事务性的。如果发生断电或其他系统故障,数据可能不会完全写入到储存中。仅当应用程序可以处理部分写入数据的情况时,PMEM 储存才适用。
28.3.1.1 可受益于较大字节可寻址储存量的应用程序 #
如果服务器托管的某个应用程序可按字节直接使用较大的快速储存量,则程序员可以使用 mmap
系统调用,将持久内存块直接放入该应用程序的地址空间,而无需使用任何附加的系统 RAM。
28.3.1.2 避免使用内核页面超速缓存 #
如果您想要节省用于页面超速缓存的 RAM,而不希望将 RAM 分配给应用程序,请避免使用内核页面超速缓存。例如,可以专门使用非易失性内存来保存虚拟机 (VM) 映像。由于这些映像不会超速缓存,因此可以减少主机上的超速缓存使用量,从而可在每台主机上配置更多的 VM。
28.3.2 将 PMEM 与 BTT 搭配使用 #
当您想要使用一组 NVDIMM 中的持久内存作为类似于磁盘的极速储存池时,此方法非常有用。例如,将文件系统日记置于带有 BTT 的 PMEM 上,可以在发生电源故障或其他突发性中断后提高文件系统恢复的可靠性(请参见第 28.5.3 节 “创建使用 BTT 的 PMEM 名称空间”)。
对于应用程序而言,此类设备仅显示为极速 SSD,并可像其他任何储存设备一样供您使用。例如,LVM 可以分布在持久内存的顶层,像平时一样正常工作。
BTT 的优点在于可以保证扇区写入的原子性,因此,即使是依赖于数据完整性的复杂应用程序也能保持正常工作。可通过标准的错误报告通道来运行媒体错误报告。
28.4 用于管理持久内存的工具 #
要管理持久内存,必须安装 ndctl
包。安装此包也会安装 libndctl
包,后者提供一组用户空间库用于配置 NVDIMM。
这些工具通过 libnvdimm
库运行。该库支持三种类型的 NVDIMM:
PMEM
BLK
同步 PMEM 和 BLK。
ndctl
实用程序提供一系列有用的手册
页。可使用以下命令访问这些页面:
tux >
ndctl help subcommand
要查看可用子命令的列表,请使用:
tux >
ndctl --list-cmds
可用的子命令包括:
- version
显示 NVDIMM 支持工具的当前版本。
- enable-namespace
使指定的名称空间可供使用。
- disable-namespace
阻止使用指定的名称空间。
- create-namespace
从指定的储存设备创建新的名称空间。
- destroy-namespace
去除指定的名称空间。
- enable-region
使指定的区域可供使用。
- disable-region
阻止使用指定的区域。
- zero-labels
擦除设备中的元数据。
- read-labels
检索指定设备的元数据。
- list
显示可用的设备。
- help
显示有关工具用法的信息。
28.5 设置持久内存 #
28.5.1 查看可用的 NVDIMM 储存 #
可以使用 ndctl
list
命令列出系统中所有可用的 NVDIMM。
在以下示例中,系统包含三个 NVDIMM,这些 NVDIMM 位于单个三通道交错集内。
root #
ndctl list --dimms
[ { "dev":"nmem2", "id":"8089-00-0000-12325476" }, { "dev":"nmem1", "id":"8089-00-0000-11325476" }, { "dev":"nmem0", "id":"8089-00-0000-10325476" } ]
如果结合不同的参数,ndctl
list
还可以列出可用的区域。
区域可能不会按数字顺序显示。
请注意,尽管只有三个 NVDIMM,但它们却显示为四个区域。
root #
ndctl list --regions
[ { "dev":"region1", "size":68182605824, "available_size":68182605824, "type":"blk" }, { "dev":"region3", "size":202937204736, "available_size":202937204736, "type":"pmem", "iset_id":5903239628671731251 }, { "dev":"region0", "size":68182605824, "available_size":68182605824, "type":"blk" }, { "dev":"region2", "size":68182605824, "available_size":68182605824, "type":"blk" } ]
空间以两种不同的形式显示:三个 BLK 类型的独立 64 GB 区域,或者一个 PMEM 类型的合并 189 GB 区域,后者将三个交错式 NVDIMM 中的所有空间表示为单个卷。
请注意,available_size
的显示值与 size
的显示值相同。这意味着尚未分配任何空间。
28.5.2 将储存配置为使用 DAX 的单个 PMEM 名称空间 #
第一个示例将三个 NVDIMM 配置成使用 Direct Access (DAX) 的单个 PMEM 名称空间。
第一个步骤是创建新的名称空间。
root #
ndctl create-namespace --type=pmem --mode=fsdax --map=memory
{ "dev":"namespace3.0", "mode":"memory", "size":199764213760, "uuid":"dc8ebb84-c564-4248-9e8d-e18543c39b69", "blockdev":"pmem3" }
这会创建支持 DAX 的块设备 /dev/pmem3
。设备名称中的 3
继承自父区域编号(在本例中为 region3
)。
--map=memory
选项从 NVDIMM 中设置出一部分 PMEM 储存空间,以便可以使用这些空间来分配称作结构页面
的内部内核数据结构。这样,便可以将新的 PMEM 名称空间与 O_DIRECT I/O
和 RDMA
等功能搭配使用。
最终 PMEM 名称空间的容量之所以小于父 PMEM 区域,是因为有一部分持久内存预留给了内核数据结构。
接下来,我们校验新的块设备是否可用于操作系统:
root #
fdisk -l /dev/pmem3
Disk /dev/pmem3: 186 GiB, 199764213760 bytes, 390164480 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 4096 bytes I/O size (minimum/optimal): 4096 bytes / 4096 bytes
与其他任何驱动器一样,在使用该设备之前,必须先将其格式化。在本示例中,我们使用 XFS 将其格式化:
root #
mkfs.xfs /dev/pmem3
meta-data=/dev/pmem3 isize=256 agcount=4, agsize=12192640 blks = sectsz=4096 attr=2, projid32bit=1 = crc=0 finobt=0, sparse=0 data = bsize=4096 blocks=48770560, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0 ftype=1 log =internal log bsize=4096 blocks=23813, version=2 = sectsz=4096 sunit=1 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0
接下来,可将新的驱动器装入到某个目录:
root #
mount -o dax /dev/pmem3 /mnt/pmem3
然后,可以校验是否获得了一个支持 DAX 的设备:
root #
mount | grep dax
/dev/pmem3 on /mnt/pmem3 type xfs (rw,relatime,attr2,dax,inode64,noquota)
结果是,我们已获得一个使用 XFS 文件系统格式化的,且装有 DAX 的 PMEM 名称空间。
对该文件系统中的文件进行任何 mmap()
调用都会返回直接映射到 NVDIMM 上的持久内存的虚拟地址,并且会完全绕过页面超速缓存。
对该文件系统中的文件进行任何 fsync
或 msync
调用仍可确保将修改后的数据完全写入到 NVDIMM。这些调用会刷新通过 mmap
映射在用户空间中修改的任何页面的关联处理器超速缓存行。
28.5.2.1 去除名称空间 #
在创建使用相同储存的其他任何类型的卷之前,我们必须卸载此 PMEM 卷,然后将其去除。
首先卸载该卷:
root #
umount /mnt/pmem3
然后禁用名称空间:
root #
ndctl disable-namespace namespace3.0
disabled 1 namespace
然后删除该卷:
root #
ndctl destroy-namespace namespace3.0
destroyed 1 namespace
28.5.3 创建使用 BTT 的 PMEM 名称空间 #
BTT 提供原子性扇区写入,因此,当您需要数据保护(例如,为 Ext4 和 XFS 日记提供数据保护)时,BTT 会是个不错的选择。如果发生电源故障,日记将受到保护且可恢复。以下示例演示如何以扇区模式创建一个带有 BTT 的 PMEM 名称空间,以及如何将文件系统日记置于此名称空间。
root #
ndctl create-namespace --type=pmem --mode=sector
{ "dev":"namespace3.0", "mode":"sector", "uuid":"51ab652d-7f20-44ea-b51d-5670454f8b9b", "sector_size":4096, "blockdev":"pmem3s" }
接下来,校验新设备是否存在:
root #
fdisk -l /dev/pmem3s
Disk /dev/pmem3s: 188.8 GiB, 202738135040 bytes, 49496615 sectors Units: sectors of 1 * 4096 = 4096 bytes Sector size (logical/physical): 4096 bytes / 4096 bytes I/O size (minimum/optimal): 4096 bytes / 4096 bytes
与前面配置的支持 DAX 的 PMEM 名称空间一样,这个支持 BTT 的 PMEM 名称空间也会占用 NVDIMM 中的所有可用储存。
设备名称 (/dev/pmem3s
) 中的尾部 s
表示扇区
(sector),可用于轻松辨别配置为使用 BTT 的名称空间。
可按前一示例中所述格式化和装入卷。
此处显示的 PMEM 名称空间不能使用 DAX。它会使用 BTT 来提供扇区写入原子性。每次通过 PMEM 块驱动程序进行扇区写入时,BTT 都会分配一个新的扇区来接收新数据。完全写入新数据后,BTT 将以原子方式更新其内部映射结构,使新写入的数据可供应用程序使用。如果在此过程中的任意时间点发生电源故障,则写入内容将会完全丢失,在这种情况下,应用程序可以访问其旧数据,而这些数据仍旧保持不变。这可以防止出现所谓“扇区撕裂”的情况。
与其他任何标准块设备一样,可以使用某个文件系统格式化这个支持 BTT 的 PMEM 名称空间,并在该文件系统中使用它。无法将该名称空间与 DAX 搭配使用。但是,此块设备中的文件的 mmap
映射将使用页面超速缓存。
28.5.4 将文件系统日记置于 PMEM/BTT 上 #
当您将文件系统日记置于一个单独的设备上时,该设备必须使用相同的文件系统块大小。此大小很有可能是 4096,您可以使用以下命令查找块大小:
root #
blockdev --getbsz /dev/sda3
以下示例在单独的 NVDIMM 设备上创建新的 Ext4 日记,并在 SATA 设备上创建文件系统,然后将新文件系统关联到日记:
root #
mke2fs -b 4096 -O journal_dev /dev/pmem3s
root #
mkfs.ext4 -J device=/dev/pmem3s /dev/sda3
以下示例在 SATA 驱动器上创建新的 XFS 文件系统,并在单独的 NVDIMM 设备上创建日记:
root #
mkfs.xfs -l logdev=/dev/pmem3s /dev/sda3
有关选项的详细信息,请参见 man 8 mkfs.ext4
和 man 8 mkfs.ext4
。
28.6 更多信息 #
可以在以下列表中找到关于此主题的更多信息:
包含有关配置 NVDIMM 系统的指导、有关测试的信息,以及有关启用 NVDIMM 的规范的链接。随着 Linux 中 NVDIMM 支持功能的不断发展,此站点的内容也会不断扩充。
有关在 Linux 和其他操作系统中配置、使用非易失性内存,以及为使用此类内存的系统编程的信息。其中介绍了 NVM 库 (NVML)。该库旨在提供有用的 API 用于在用户空间中进行持久性内存编程。
此文档面向内核开发人员,包含在当前 Linux 内核树的“文档”文件夹中。其中探讨了涉及启用 NVDIMM 的不同内核模块,列出了有关内核实现的一些技术细节,并介绍了
ndctl
工具使用的sysfs
内核接口。用于管理 Linux 内核中的
libnvdimm
子系统的实用程序库。另外还包含用户空间库,以及单元测试和文档。