支持虚拟持久内存¶
https://blueprints.launchpad.net/nova/+spec/virtual-persistent-memory
QEMU 和 libvirt 现在都支持虚拟持久内存。本规范旨在在 OpenStack Nova 中启用此支持。
问题描述¶
多年来,计算机应用程序将其数据组织在两个层级之间:内存和存储。新兴的 持久内存 技术引入了第三个层级。持久内存(或简称 pmem)的访问方式类似于易失性内存,使用处理器加载和存储指令,但它像存储一样在断电后仍能保留其内容。
虚拟化层已经支持虚拟持久内存,这意味着虚拟机现在可以将物理持久内存作为虚拟持久内存的后端。就 Nova 而言,需要解决几个问题
如何管理和呈现物理持久内存作为虚拟持久内存
持久内存的发现和资源跟踪
用户如何指定所需的虚拟持久内存量
虚拟持久内存的生命周期是什么
用例¶
为应用程序提供加载能够跨电源循环保留数据的、大段连续内存的能力。
除了数据持久性之外,持久内存比 DRAM 更便宜,并且具有更大的容量。对于请求大量内存的场景(例如高性能计算 (HPC)),这是一个有吸引力的特性。
已经有一些应用程序进行了探索,这些应用程序大量使用内存设备,例如内存数据库。例如:redis、rocksdb、oracle、SAP HANA 和 Aerospike。
注意
本规范仅旨在为 libvirt KVM 驱动程序启用虚拟持久内存。
提议的变更¶
背景¶
应用程序使用持久内存的最有效方式是将持久内存的一部分内存映射 (mmap()) 到应用程序的地址空间。完成映射后,应用程序将 直接(也称为 直接 访问)访问持久内存,这意味着无需通过内核或其他中间软件。持久内存有两种硬件接口——“PMEM”和“BLK”。由于“BLK”采用孔径模型访问持久内存,因此不支持 直接 访问。为了提高效率,本规范建议仅将通过“PMEM”接口访问的持久内存用作 QEMU 虚拟化持久内存的后端。
持久内存必须被划分为 pmem 命名空间 才能供应用程序使用。pmem 命名空间有几种模式,适用于不同的使用场景。模式 devdax 和模式 fsdax 都支持 直接 访问。模式 devdax 为命名空间提供一个字符设备,因此应用程序可以将整个命名空间 mmap() 到其地址空间。而模式 fsdax 提供一个块设备。建议使用模式 devdax 将持久内存分配给虚拟机。请参阅 虚拟 NVDIMM 后端 和 NVDIMM Linux 内核文档 以获取详细信息。
重要
因此,本规范建议仅将处于 devdax 模式下的持久内存命名空间用作 QEMU 虚拟持久内存后端。
devdax 持久内存命名空间需要连续的物理空间,并且不像普通系统内存那样以页面进行管理。这给多个命名空间的创建和多个应用程序的使用带来了碎片化问题。如图下所示,四个应用程序正在使用四个大小为 100GB 的命名空间
+-----+ +-----+ +-----+ +-----+
|app1 | |app2 | |app3 | |app4 |
+--+--+ +--+--+ +--+--+ +--+--+
| | | |
| | | |
+----v----+----v----+----v----+-----v---+
| | | | |
| 100GB | 100GB | 100GB | 100GB |
| | | | |
+---------+---------+---------+---------+
在 app2 和 app4 终止后,结果如下
+-----+ +-----+
|app1 | |app3 |
+--+--+ +--+--+
| |
| |
+----v----+---------+----v----+---------+
| | | | |
| 100GB | 100GB | 100GB | 100GB |
| | | | |
+---------+---------+---------+---------+
可用空间的总大小为 200GB。但是,无法创建大小为 200GB 的 devdax 模式命名空间。
持久内存命名空间管理和资源跟踪¶
由于上述碎片化问题,持久内存无法像系统内存那样进行管理。换句话说,在 VM 创建和删除时动态创建和删除持久内存命名空间会导致碎片化,并且还会对持久内存资源的跟踪提出挑战。建议的方法是使用预先创建的固定大小的命名空间。换句话说,云管理员在 Nova 部署到某个主机之前创建所需的持久内存大小。然后,云管理员将命名空间信息放入 nova 配置文件中(如下所示)。Nova 计算代理通过解析配置文件来发现命名空间,以确定它可以分配给客户机的命名空间。发现的持久内存命名空间将作为与 ROOT 资源提供程序关联的自定义资源类的库存报告给 placement 服务。
自定义资源类用于表示持久内存命名空间资源。正在使用的自定义资源类的命名约定是
CUSTOM_PMEM_NAMESPACE_$LABEL
$LABEL 是管理员定义的与特定数量的持久内存命名空间关联的资源类名称的可变部分。通常,它是以任何所需单位表示的命名空间的大小。它也可以是描述容量的字符串,例如“SMALL”、“MEDIUM”或“LARGE”。管理员应为每个命名空间正确定义“$LABEL”的值。
$LABEL 与持久内存命名空间之间的关联由新的配置选项“CONF.libvirt.pmem_namespaces”定义。此配置选项是以下格式的字符串类型
"$LABEL:$NSNAME[|$NSNAME][,$LABEL:$NSNAME[|$NSNAME]]"
$NSNAME 是属于名为 CUSTOM_PMEM_NAMESPACE_$LABEL 的资源类的持久内存命名空间的名称。可以通过 ndctl 命令的“-n/--name”选项在创建持久内存命名空间时为其命名。
例如,在某个主机上,可能存在以下配置
"128G:ns0|ns1|ns2|ns3,262144MB:ns4|ns5,MEDIUM:ns6|ns7"
上述配置的解释是,该主机具有 4 个资源类为 CUSTOM_PMEM_NAMESPACE_128G 的持久内存命名空间(ns0、ns1、ns2、ns3),2 个资源类为 CUSTOM_PMEM_NAMESPACE_262144MB 的命名空间(ns4、ns5),以及 2 个资源类为 CUSTOM_PMEM_NAMESPACE_MEDIUM 的命名空间(ns6、ns7)。
库存的“total”值是属于该资源类的持久内存命名空间的数量。
“max_unit”设置为与“total”相同的值,因为可以将某个资源类中的所有持久内存命名空间附加到一个实例。
“min_unit”和“step_size”的值为 1。
“allocation_ratio”的值为 1.0。
在上述示例中,对该资源提供程序库存的 GET 请求的响应是
"inventories": {
...
"CUSTOM_PMEM_NAMESPACE_128GB": {
"allocation_ratio": 1.0,
"max_unit": 4,
"min_unit": 1,
"reserved": 0,
"step_size":1,
"total": 4
},
"CUSTOM_PMEM_NAMESPACE_262144MB": {
"allocation_ratio": 1.0,
"max_unit": 2,
"min_unit": 1,
"reserved": 0,
"step_size": 1,
"total": 2
},
"CUSTOM_PMEM_NAMESPACE_MEDIUM": {
"allocation_ratio": 1.0,
"max_unit": 2,
"min_unit": 1,
"reserved": 0,
"step_size": 1,
"total":2
},
...
}
请注意,这只是一个示例,用于显示配置持久内存命名空间的各种方式以及如何跟踪它们。在资源类名称的命名方面肯定存在一些灵活性。管理员应正确配置命名空间。
注意
资源类名称是不透明的。例如,即使它们(可能)大小相同,对 CUSTOM_PMEM_NAMESPACE_128GB 的请求也无法由 CUSTOM_PMEM_NAMESPACE_131072MB 资源满足。
不同的单位在嵌入到自定义资源类名称中时不能自由地相互转换。这意味着对 128GB 持久内存命名空间的请求可以由 CUSTOM_PMEM_NAMESPACE_128GB 资源满足,但不能由 CUSTOM_PMEM_NAMESPACE_131072MB 资源满足,即使它们具有相同的数量。
持久内存本质上对 NUMA 敏感。但是对于初始迭代,库存直接放在计算主机的 ROOT 资源提供程序下。持久内存 NUMA 亲和性将由单独的后续规范来解决。
配置中的更改将阻止 nova 计算代理(重新)启动,如果该更改删除了正在被客户机使用的配置中的任何命名空间。
虚拟持久内存规范¶
虚拟持久内存信息以以下形式添加到客户机硬件 flavor extra specs 中
hw:pmem=$LABEL[,$LABEL]
$LABEL 是 持久内存命名空间管理和资源跟踪 部分中定义的资源类名称的可变部分。每个“$LABEL”的外观表示对 CUSTOM_PMEM_NAMESPACE_$LABEL 资源类的持久内存命名空间的一个要求。因此,在一种规范中可以多次出现相同的 $LABEL。例如
hw:pmem=128GB,128GB
这意味着对两个 128GB 持久内存命名空间的需求。
Libvirt 域规范要求将每个虚拟持久内存与一个客户机 NUMA 节点关联。如果在 flavor 中指定了客户机 NUMA 拓扑,则将客户机虚拟持久内存设备放在客户机 NUMA 节点 0 下。如果 flavor 中未指定客户机 NUMA 拓扑,则隐式地构造一个客户机 NUMA 节点 0,并将所有客户机虚拟持久内存设备放在其下。请注意,在第二种情况下(隐式构造客户机 NUMA 节点 0),NUMA 拓扑逻辑发生在 Nova API 中,这意味着 Nova 的任何其他部分都将此客户机视为 NUMA 客户机。
示例
One NUMA node, one 512GB virtual persistent memory:
hw:numa_nodes=1
hw:pmem=512GB
One NUMA node, two 512GB virtual persistent memory:
hw:numa_nodes=1
hw:pmem=512GB,512GB
Two NUMA nodes, two 512GB virtual persistent memory:
hw:numa_nodes=2
hw:pmem=512GB,512GB
Both of the two virtual persistent memory devices
are put under NUMA node 0.
No NUMA node, two 512GB virtual persistent memory:
hw:pmem = 512GB,512GB
A guest NUMA node 0 is constructed implicitly.
Both virtual persistent memory devices are put under it.
重要
Qemu 不支持通过多个物理持久内存命名空间(无论它们是否连续)来支持一个虚拟持久内存设备。因此,客户机请求的任何虚拟持久内存设备都由具有相同资源类的单个物理持久内存命名空间支持。
extra specs 相应地转换为 placement API 请求。
虚拟持久内存处置¶
由于主机 PMEM 命名空间的持久性,一旦虚拟持久内存不再与任何 VM 实例关联(例如 VM 删除、冷/实时迁移、shelve、evacuate 等),就应立即将虚拟持久内存的内容清零。否则,将存在安全问题。由于持久内存设备通常很大,这可能会给客户机删除或涉及擦除 PMEM 命名空间的任何其他操作带来性能损失。无法使用 DAX(直接访问)设备使用标准的 I/O API(读/写)。Nova 计算 libvirt 驱动程序使用 daxio 实用程序(由 privsep 库函数包装)来实现此目的。
VM 重建¶
在 VM 重建期间,持久内存命名空间被清零,以恢复 VM 的初始状态。
VM 调整大小¶
允许调整大小到具有任意虚拟持久内存设备的新的 flavor。原始虚拟持久内存的内容不会复制到新的虚拟持久内存(如果有)。
实时迁移¶
QEMU 支持具有虚拟持久内存的实时迁移。Qemu 在实时迁移的情况下将虚拟持久内存视为易失性内存。由于虚拟持久内存的典型大容量,它需要更长的时间。
虚拟持久内存热插拔¶
本规范未涉及虚拟持久内存的热插拔。
VM 快照¶
当前的 VM 快照不包括内存镜像。对于当前阶段,虚拟持久镜像不包含在 VM 快照中。将来,虚拟持久镜像可以作为单独的镜像格式存储在 Glance 中。flavor extra specs 可用于指定在 VM 快照期间是否保存虚拟持久内存镜像。
VM shelve/unshelve¶
shelve VM 是将 VM 快照上传到 Glance 服务。由于虚拟持久内存镜像不包含在 VM 快照中,VM shelve/unshelve 不会自动保存/恢复当前的虚拟持久内存。与快照一样,在持久内存镜像可以存储在 Glance 中后,可以支持保存/恢复虚拟持久内存镜像。shelved VM 所属的持久内存命名空间在 VM 被 shelve-offloaded 后被清零。
备选方案¶
可以根据 VM 创建/删除动态创建/销毁持久内存命名空间。这种方式比固定的方法更灵活,但是,如 背景 部分所述,它会导致碎片化。
另一种固定大小的方法是均匀地将整个持久内存空间划分为相同大小的命名空间,并将持久内存资源提供程序的“step_size”设置为每个命名空间的大小。但是,此模型假定可以从多个较小的命名空间组装一个较大的命名空间(256GB 的持久内存需求可能落在 2x128GB 命名空间上),但事实并非如此。
持久内存与块设备在非易失性性质和生命周期管理方面表现出某些相似之处。可以将它插入块设备映射 (BDM) 接口。但是,持久内存的 NUMA 亲和性是持久内存的未来,BDM 不是描述 NUMA 的理想接口。
数据模型影响¶
引入了一个新的 LibvirtVPMEMDevice 对象来跟踪实例的虚拟 PMEM 信息,它代表由物理持久内存命名空间支持的虚拟持久内存设备
class LibvirtVPMEMDevice(ResourceMetadata):
# Version 1.0: Initial version
VERSION = "1.0"
fields = {
'label': fields.StringField(),
'name': fields.StringField(),
'size': fields.IntegerField(),
'devpath': fields.StringField(),
'align': fields.IntegerField(),
}
类 InstanceExtra 中的“resources”延迟加载列存储给定实例的序列化 ResourceList 对象,每个 Resource 对象包含特定的资源信息,它具有对象字段“metadata”,该字段可以是 ResourceMetadata 对象的子类。由于引入了 LibvirtVPMEMDevice,虚拟持久内存信息可以存储在对象 Instance 的“resources”字段中,并持久保存在数据库表 InstanceExtra 中。
REST API 影响¶
flavor extra specs 已经接受任意数据。没有引入新的微版本。
安全影响¶
主机持久内存命名空间需要被擦除(清零)才能被重用。
通知影响¶
无。
其他最终用户影响¶
最终用户选择具有所需虚拟持久内存大小的 flavor。
性能影响¶
PMEM 命名空间往往很大。清零持久内存命名空间需要相当长的时间。这可能会在删除具有大型虚拟持久内存的客户机时引入负性能影响。
其他部署者影响¶
部署者需要在 nova 部署到某个主机之前创建所需的持久内存命名空间。
开发人员影响¶
无。
升级影响¶
无。
实现¶
负责人¶
- 主要负责人
xuhj
- 其他贡献者
luyaozhong rui-zang
工作项¶
对象:添加 DB 模型和 Nova 对象。
计算:虚拟持久内存生命周期管理。
- 调度器:将虚拟持久内存请求转换为
placement 请求。
API:解析虚拟持久内存 flavor extra specs。
依赖项¶
内核版本 >= 4.18
注意
Linux 内核 v4.0 或更新版本支持 NVDIMM。 建议使用内核版本 4.2 或更高版本,因为 NVDIMM 支持 默认启用。 我们在较旧的版本中遇到了一些错误,并且我们已在 4.18 版本上使用 OpenStack 完成了所有验证工作,因此 4.18 版本及更新版本很可能保证其功能。
QEMU 版本 >= 3.1.0
Libvirt 版本 >= 5.0.0
ndctl 版本 >= 62
daxio 版本 >= 1.6
测试¶
单元测试。 需要第三方 CI 在真实硬件上进行测试。 QEMU/KVM 支持持久内存嵌套虚拟化。 对于第三方 CI,将在具有物理持久内存支持的虚拟持久内存的 VM 中执行 tempest 测试。
文档影响¶
云管理员文档需要描述如何创建和配置持久内存命名空间。 将持久内存部分添加到 Nova “高级配置”文档中。
需要让最终用户了解此功能。 将 flavor extra spec 细节添加到 Nova flavors 文档中。
参考资料¶
历史¶
发布名称 |
描述 |
|---|---|
Train |
引入 |