Author 晓兵

weixin: ssbandjl

公众号: 云原生云

云原生云

在存储性能开发套件 (SPDK) 中启用持久内存(PM)

原创 晓兵XB 云原生云 2023-04-30 10:21 发表于四川

https://mp.weixin.qq.com/s/trDKiEoYBjD8-1zhmEMYnA

图片

背景

Optane 是一种内存系统,旨在通过桥接存储和 RAM 来提高硬盘驱动器 (HDD) 和速度较慢的 SATA SSD 的性能。

2022年7月, 英特尔首席执行官 Pat Gelsinger 将关闭 Optane 的决定归因于更广泛的行业转向 Compute Express Link (CXL) 架构

英特尔第二季度财报电话会议中的公告之一是确认该公司将关闭其 Optane 内存部门

虽然傲腾停产, 但是其技术思想仍然值得学习, 作为代替 Optane 持久内存,英特尔的官方策略是转向 CXL 内存技术 (CXL.mem),该技术允许通过支持 CXL 的 PCIe 总线将易失性和非易失性内存连接到 CPU。这将实现与 Optane(非易失性内存、大容量)相同的许多目标,而无需开发完全独立的内存技术。Sapphire Rapids 又将是英特尔首款支持 CXL 的 CPU,整体技术拥有更广泛的行业支持

介绍

随着新存储技术的发展以及随之而来的对更高性能的期望,业界已经开始寻找向内存通道迁移的可能性。

提供更高性能期望的存储技术的新方向是非易失性双列直插式内存模块 (NVDIMM)。

NVDIMM 是非易失性内存,允许随机访问。非易失性意味着即使断电也能保存数据,因此在意外断电、系统崩溃和正常关机期间我们不会遇到数据丢失的情况。同时,NVDIMM 采用兼容标准 DIMM 插槽的双列直插式内存模块 (DIMM) 封装,通过标准双倍数据速率 (DDR) 总线进行通信。考虑到它是非易失性的并且与传统的动态随机存取存储器(DRAM)接口兼容,它也被称为持久存储器(PMEM)。

类型

根据标准化机构JEDEC提供的定义,目前NVDIMM分为三种,分别介绍如下。

NVDIMM-N

NVDIMM-N 在一个模块中包含闪存和传统 DRAM,计算机可以直接访问,并支持字节和块寻址。在意外断电后,NVDIMM-N 备用电源可以提供足够的电力将数据从 DRAM 复制到闪存,当电力恢复时,数据可以重新加载到 DRAM 中。

![图片](data:image/svg+xml,%3C%3Fxml version=‘1.0’ encoding=‘UTF-8’%3F%3E%3Csvg width=‘1px’ height=‘1px’ viewBox=‘0 0 1 1’ version=‘1.1’ xmlns=‘http://www.w3.org/2000/svg' xmlns:xlink=‘http://www.w3.org/1999/xlink'%3E%3Ctitle%3E%3C/title%3E%3Cg stroke=‘none’ stroke-width=‘1’ fill=‘none’ fill-rule=‘evenodd’ fill-opacity=‘0’%3E%3Cg transform=‘translate(-249.000000, -126.000000)’ fill='%23FFFFFF’%3E%3Crect x=‘249’ y=‘126’ width=‘1’ height=‘1’%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E) 图 1. NVDIMM-N。

事实上,NVDIMM-N 主要像传统 DRAM 一样工作,这就是为什么它的延迟也发生在 10 -8秒的水平。至于容量,受尺寸限制,NVDIMM-N 与传统 DRAM 相比改进有限。

一个缺点是 NVDIMM-N 闪存不可寻址,另一个缺点是使用两种介质类型会大大增加其成本。然而,NVDIMM-N 以其持久内存的新概念给业界留下了深刻印象。目前市场上有很多基于NVDIMM-N的产品。

NVDIMM-F

NVDIMM-F是闪存,使用DRAM的DDR3或DDR4总线,而我们知道,以NAND闪存为介质的固态硬盘(SSD)一般使用Serial Advanced Technology Attachment(SATA)、Serial Attached SCSI(SAS) ), 或 PCIe* 总线。使用DDR总线可以提高最大带宽,一定程度上降低协议带来的延迟和成本,但它只支持块寻址。

NVDIMM-F 的工作原理与 SSD 基本相同,这就是为什么它的延迟在 10 -5秒的水平。它的容量可以轻松扩展到太字节 (TB)。

NVDIMM-P

与该类型相关的标准目前正在制定中。有望与DDR5标准一起出台。根据发布计划,DDR5将提供两倍于DDR4的带宽,并提升通道效率。对于 NVDIMM-P,这些预期的改进,结合其用于服务器和客户端平台的用户友好界面,可在应用程序中实现高性能和改进的电源管理。

NVDIMM-P 结合了 DRAM 和闪存的特性,既支持块寻址,也支持传统的类 DRAM 字节寻址,具有与 NAND 闪存一样可能的 TB 容量。此外,它可以将延迟保持在10 -7秒以内。

通过直接连接到内存总线的数据介质,CPU 可以直接访问数据,没有驱动器或 PCIe 延迟。同时,不需要块访问,CPU 可以只访问它需要的数据,因为内存访问是通过 64 字节的高速缓存行进行的。

Intel 公司于 2019 年 4 月发布了Intel® Optane™ DC 持久内存。它可以看作是 NVDIMM-P 实现的一个实例。

图片 图 2.英特尔® 傲腾™ DC 持久内存。

硬件支持

应用程序可以像访问传统 DRAM 一样直接访问 NVDIMM-P,这也省去了传统块设备和内存之间进行页面交换的需要。但是,向持久内存写入数据和向普通DRAM写入数据共享计算机资源,包括处理器缓冲区、L1/L2缓存等。

需要注意的是,为了使数据持久化,需要将数据写入到持久化存储设备或具有掉电保护的缓冲区中。软件要想充分利用持久内存的特性,指令集架构至少需要支持以下特性。

原子写

原子性意味着对持久内存的任何大小的写入都应该是原子的,因为这可以防止由于系统崩溃或意外断电而导致的错误数据或重复写入。IA-32 (IA32) 和 IA-64 (IA64) 处理器可以保证数据访问(对齐或未对齐)的原子写入,以缓存高达 64 位的数据;因此,软件可以安全地更新持久内存中的数据。这也提高了性能,因为它避免了用于确保写入原子性的写时复制或预写日志记录的使用。

高效缓存刷新

出于性能原因,持久内存中的数据在被访问之前必须放入处理器缓存中。优化的缓存刷新指令可以减少刷新 (CLFLUSH) 对性能的影响。

CLFLUSHOPT提供更高效的缓存刷新指令。

缓存行回写 ( CLWB ) 指令将缓存行上更改的数据写回内存(类似于CLFLUSHOPT),无需将此缓存行变为无效(MESI 协议),而是进入未更改的独占状态. CLWB实际上是在试图减少由于刷新某些缓存行而在下次访问中不可避免的缓存未命中。

提交到持久层

在现代计算机的体系结构中,缓存刷新完成后,修改后的数据将写回内存子系统的写缓冲区。但是,在这种情况下,数据是不持久的。为确保数据写入持久内存,软件需要刷新内存子系统中的易失性写入缓冲区或其他缓存。用于持久写入的提交指令PCOMMIT可以将内存子系统的写入队列中的数据提交到持久内存。

(注意:支持 Intel® Optane™ DC 持久内存的平台还需要支持异步 DRAM 刷新 (ADR)。此功能通过自动刷新内存控制器中的写入挂起队列 (WPQ) 来保证电源故障或关机期间的数据持久性, 消除了对PCOMMIT的需要。有关更多信息,请参阅弃用 PCOMMIT 指令)

非临时存储优化

当软件需要将大量数据从普通内存复制到持久内存(或持久内存之间)时,弱序、非临时存储操作(例如,MOVNTI)指令是可用的选项。因为非临时存储指令可以隐式地使要写回的缓存行无效,所以软件不需要显式刷新缓存行(参见英特尔® 64 和 IA-32 架构软件开发人员手册第 1 卷第 10.4.6.2节).

以上介绍了NVDIMM的几种实现方式,以及硬件优化和支持,以充分发挥NVDIMM-P的性能。以下部分是关于软件支持,包括编程模型、编程库、存储性能开发工具包(SPDK)支持等。

软件支持

本节介绍支持软件可以提供以完全启用 NVDIMM 功能。有些人可能想知道为什么 NVDIMM 并不像名称所暗示的那样方便;对于持久内存来说,距离重启电脑一切如常关机的理想使用场景还差得很远。事实上,这在不久的将来仍然很难实现,因为例如在 DRAM 之上,高速缓存和寄存器仍然是易失性的。持久内存本身并不能使所有内容持久化。还有一个问题:内存泄漏。如果发生内存泄漏,重启会清除易失性内存,但是持久性内存泄漏呢?这是一个艰难的局面。PMEM 在某些方面类似于内存,在其他方面类似于存储;但是,一般来说,我们不会将 PMEM 视为能够替代内存或存储的东西。

自 17.10 版本以来,SPDK 已包含对 PMEM 的支持。PMEM在SPDK的bdev层暴露为块设备,通过块设备接口与上层通信,如图3所示。

![图片](data:image/svg+xml,%3C%3Fxml version=‘1.0’ encoding=‘UTF-8’%3F%3E%3Csvg width=‘1px’ height=‘1px’ viewBox=‘0 0 1 1’ version=‘1.1’ xmlns=‘http://www.w3.org/2000/svg' xmlns:xlink=‘http://www.w3.org/1999/xlink'%3E%3Ctitle%3E%3C/title%3E%3Cg stroke=‘none’ stroke-width=‘1’ fill=‘none’ fill-rule=‘evenodd’ fill-opacity=‘0’%3E%3Cg transform=‘translate(-249.000000, -126.000000)’ fill='%23FFFFFF’%3E%3Crect x=‘249’ y=‘126’ width=‘1’ height=‘1’%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E) 图 3.SPDK 中的 PMEM 支持。

从图中我们可以看出libpmemblk把块操作变成了字节操作,但是它是如何实现的呢?在深入研究libpmemblk和底层持久内存开发工具包 (PMDK)之前,让我们先了解一下基础知识。

Mmap 和 DAX

让我们先来看看传统的I/O;即缓冲 I/O。大多数操作系统默认使用缓存 I/O,这允许 I/O 数据缓存在操作系统页面缓存中,这意味着数据首先被复制到操作系统内核空间缓冲区,然后从那里复制到指定的用户地址空间。

// A Programmer’s view (not just C programmers!)
fd = open(”/my/file”, O_RDWR);
…
count = read(fd, buf, bufsize);
…
count = write(fd, buf, bufsize);
…
close(fd);
// “Buffer-Based”

在 Linux* 中,这种文件访问技术是通过读/写系统调用实现的,如图 4 所示。接下来,我们对比一下,看看内存映射 I/O mmap() 是如何工作**的**。

// A Programmer’s view (mapped files)
fd = open(”/my/file”, O_RDWR);
…
base = mmap(NULL, filesize, PROT_READ|PROT_WRITE,
  MAP_SHARED, fd, 0);
close(fd);
…
base[100] = ’X’; 
strcpy(base, ”hello there”);
*structp = *base_structp;
…
// “Load/Store”

我们可以通过mmap获取对应文件的指针,然后像我们在内存中操作一样赋值或者执行 memcpy/strcpy。我们称这个过程为加载/存储操作,它通常需要调用msyncfsync来持久化数据。

mmap所做的可以看作是直接将文件复制到用户空间,因为它建立了文件和用户空间之间的映射,所以节省了一份数据。但是,mmap仍然依赖于页面缓存。

图片 图 4. 加载/存储仍然需要页面缓存。

现在,DAX 是什么?DAX,意思是直接访问,是一个基于 mmap 的特性。但它与mmap的不同之处在于它完全独立于页面缓存并且直接访问存储设备。这使其非常适合 NVDIMM。应用程序对 mmap 的文件操作直接同步到 NVDIMM。DAX 现在在 XFS、EXT4 和 Windows* NTFS 上受支持,但它的使用需要对应用程序或文件系统进行一些修改。

![图片](data:image/svg+xml,%3C%3Fxml version=‘1.0’ encoding=‘UTF-8’%3F%3E%3Csvg width=‘1px’ height=‘1px’ viewBox=‘0 0 1 1’ version=‘1.1’ xmlns=‘http://www.w3.org/2000/svg' xmlns:xlink=‘http://www.w3.org/1999/xlink'%3E%3Ctitle%3E%3C/title%3E%3Cg stroke=‘none’ stroke-width=‘1’ fill=‘none’ fill-rule=‘evenodd’ fill-opacity=‘0’%3E%3Cg transform=‘translate(-249.000000, -126.000000)’ fill='%23FFFFFF’%3E%3Crect x=‘249’ y=‘126’ width=‘1’ height=‘1’%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E) 图 5.DAX。

NVM 编程模型

非易失性内存 (NVM) 编程模型大致定义了三种使用持久内存的方式。

![图片](data:image/svg+xml,%3C%3Fxml version=‘1.0’ encoding=‘UTF-8’%3F%3E%3Csvg width=‘1px’ height=‘1px’ viewBox=‘0 0 1 1’ version=‘1.1’ xmlns=‘http://www.w3.org/2000/svg' xmlns:xlink=‘http://www.w3.org/1999/xlink'%3E%3Ctitle%3E%3C/title%3E%3Cg stroke=‘none’ stroke-width=‘1’ fill=‘none’ fill-rule=‘evenodd’ fill-opacity=‘0’%3E%3Cg transform=‘translate(-249.000000, -126.000000)’ fill='%23FFFFFF’%3E%3Crect x=‘249’ y=‘126’ width=‘1’ height=‘1’%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E) 图 6. NVM 编程模型。

  • 管理,如图6左侧所示,主要通过驱动提供的API对NVDIMM进行管理,如容量检查、健康状态、固件版本、固件升级、模式配置等。

  • 图 6 的中间部分显示了作为存储块设备的用法。使用支持 NVDIMM 驱动程序的文件系统和内核。应用程序无需做任何修改,通过标准的文件接口访问NVDIMM。

  • 第三种使用方式是基于文件系统的DAX特性;它通过加载/存储进行操作,并在不需要页面缓存的情况下同步保存数据。此外,不涉及系统调用或中断。这些功能是 NVM 编程模型的核心,最大限度地发挥了 NVIDMM 的潜在功能。但缺点是应用程序可能需要进行一些更改。

持久内存开发套件 (PMDK)

libpmemblk实现驻留在持久内存中的相同大小的块数组。其中的每个块都保持原子事务性,以防突然断电、程序崩溃等。它基于libpmem库。

libpmem是 PMDK 提供的低级库,用于刷新和持久化 NVDIMM 中的数据。它可以跟踪 PMEM 上的每个存储操作并确保数据持久化。

此外,PMDK 还提供了其他编程库,如libpmemobjlibpmemloglibvmmalloc等。请访问pmem.io了解更多信息。

SPDK实战——Bdevperf测试

bdevperf是SPDK中提供的性能评估工具。用户可以在 SPDK bdev层启用各种块设备并运行bdevperf测试。

步骤 1. 创建 PMEM bdev

克隆或下载 repo 并进入 SPDK 目录。

   ./configure --with-pmdk 
   make

PMDK 已包含在一些新发布的 Linux 版本中。如果配置中碰巧有错误,请访问GitHub* 站点以安装 PMDK 库。

首先,我们需要运行一个 SPDK 目标。SPDK为不同的用途提供了几个target,例如ISCSI target、NVMF target、vhost target等。这里我们运行一个简单的target spdk_tgt,仅用于接收和解析RPC命令:

./app/spdk_tgt/spdk_tgt

接下来,我们可以通过SPDK RPC命令创建一个pmem_pool

rpc.py create_pmem_pool /path/to/pmem_pool  (MB) > <BlockSize> 

如果我们这里没有真正的NVDIMM来测试,我们可以只选择一个随机路径pmem_pool(用于模拟);例如:

rpc.py create_pmem_pool /mnt/pmem  128  4096

如果您的系统中有英特尔® 傲腾™ DC 持久内存,您可以参考《快速入门指南:在 Linux* 上配置英特尔® 傲腾™ DC 持久内存》进行配置。**配置完成后,将挂载目录作为pmem_pool**的路径即可。

我们还可以使用pmem_pool_info获取创建pmem_pool所需的信息:

rpc.py pmem_pool_info /path/to/pmem_pool

或者,我们可以删除刚刚创建的pmem_pool

rpc.py delete_pmem_pool /path/to/pmem_pool

然后,我们在我们创建的pmem_pool上设置一个bdev块设备:

rpc.py construct_pmem_bdev /path/to/pmem_pool -n pmem_bdev_name

步骤 2. 更新配置文件

将路径更改为spdk/test/bdev/bdev.conf.in,并且只保留部分 PMEM 配置。

[Pmem] 
Blk <pmemblk pool file name> <bdev name>

例如:

[Pmem] 
Blk  /mnt/pmem-pool  pmem-bdev

步骤 3. bdevperf 测试

./bdevperf -c ../bdev.conf.in -q <iodepth> -t <time> -w <io pattern type: write|read|randwrite|randread>-o <io size in bytes>

示例命令:

./bdevperf -c ../bdev.conf.in -q 128 -t 100 -w write -o 4096 
./bdevperf -c ../bdev.conf.in -q 128 -t 100 -w write -o 4096 

结论

在本文中,我们描述了将 NVDIMM 作为存储的硬件和软件之间的差异。Intel公司于2019年4月发布了Intel® Optane™ DC Persistent Memory,使NVDIMM成为业界关注的焦点。

参考

英特尔® 架构指令集扩展编程参考

pmem.io

spdk.io

联合电子管工程委员会 (JETEC ) 技术重点领域主存储器:DDR4 和 DDR5 SDRAM

Intel® Optane™ DC Persistent Memory 的操作模式

英特尔® 傲腾™ 内存:两种令人困惑的模式第 4 部分:模式比较 - SSD 专家

关于作者

Chunyang Hui,英特尔软件工程师,主要从事存储软件的SPDK开发和性能优化。

2019 年 7 月 25 日

原文: https://www.intel.com/content/www/us/en/developer/articles/technical/enabling-persistent-memory-in-the-storage-performance-development-kit-spdk.html