PMEM 扩展系统内存用法介绍
Lapin Gris Lv3

在介绍 pmem 的几种用法之前,我们先来介绍 pmem 的几种模式,因为后面介绍的用法与 pmem 的这几种模式是分不开的。

PMEM 的三种模式

1、Memory Mode

pmem 配置为内存模式时,pmem 作为系统内存(system ram),原有的系统内存作为 cache。pmem 本身是比 DRAM 慢的,这种情况下,应用的访存延迟也会上升。内存模式屏蔽了本身的系统内存,针对虚拟化场景下一台物理机插了好几个内存的情况 几百G 的内存相当于被浪费了。

2、App Direct Mode

pmem 配置为 AD 模式时,这种模式,pmem 作为一个额外的内存资源暴露给 OS。通常情况下,我们也是采用 AD 模式,然后将 pmem 配置为 system-ram ,这样针对 redis 这种大内存的场景提供了大内存的适中的解决方案,因为 pmem 比 DRAM 便宜不少,完全采用 DRAM 比较贵。

3、Mixed Mode

用的少,混合模式的意思是,一部分配置为内存模式,剩下的容量自动为 AD 模式(配置内存模式时容量不配置为 100% 即代表混合模式)
pmem 提供了低成本大容量的内存解决方案。在 pmem 的三种模式的选择中,一般选择将 pmem 配置为 AD 模式来扩展系统内存,为 redis 等数据库场景提供更廉价的内存方案(相对来说,性能比完全采用 DRAM 会低一些)。

PMEM 的用法

a) 用作磁盘

将原有的 NVME SSD盘换成 pmem,可以获得更高的IOPS和带宽、更低的延时,解决性能瓶颈问题。

ndctl create-namespace --region region0 --mode fsdax

mkfs -t ext4 /dev/pmem0 && \
mkdir /mnt/sdb && \
mount -o dax,noatime /dev/pmem0 /mnt/sdb

执行 df -h 查看刚刚挂载的磁盘。

b) 用作 ram(DRAM 作为 cache)

将 pmem 当做一个系统内存来使用,原有的系统内存会看做一层 cache。这种用法下, pmem 是易失的,和 DRAM 的易失特性一样。这种用法,唯一的感觉是比较浪费,系统原有的内存被当做 cache 了,没有得到好的运用。

c) 用作 numa node

pmem 的另一个种用法是当做一个 numa node。当机器上被插上几根 pmem 内存时,pmem 内存会被识别为 numa 节点(配置方式如下),相较于 用作 ram 的方式,优点是显而易见的,扩展了系统可用内存。原有的系统内存也不会对上层屏蔽掉,依然可以被上层应用使用。

现在的数据中心级别的服务器操作系统通常都会配置大页来获得更好的性能。通常的大页配置为 2M 大页和 1G 大页。这里我们也介绍在 pmem 所在的 numa node 开启大页。

开启 2M 大页

daxctl migrate-device-model

# 创建 namespace
ndctl create-namespace --region=region0 --mode=devdax

# 将 dax 设陪配置为 system-ram 模式
daxctl reconfigure-device dax0.0 --mode=system-ram

# 分配 1024 个 2M 大页
echo 1024 > /sys/devices/system/node/node2/hugepages/hugepages-2048kB/nr_hugepages

# 查看 2M 页分配结果
cat /sys/devices/system/node/node2/hugepages/hugepages-2048kB/nr_hugepages
1024

cat nr_hugepages 返回值可以看到,成功开启了 1024 个 hugepage。
注:dax 设备默认的对齐就是 2M,所以 ndctl create-namespace 可以省略掉对齐参数。

开启 1G 大页

我们按照下面的方式开启 1G 大页,

daxctl migrate-device-model

# 按照 1G 对齐
ndctl create-namespace --region=region0 --align 1g --mode=devdax

# 将 dax 设陪配置为 system-ram 模式
daxctl reconfigure-device dax0.0 --mode=system-ram

# 分配 248 个 1G 内存页
echo 248 > /sys/devices/system/node/node2/hugepages/hugepages-1048576kB/nr_hugepages

# 查看 1G 页分配结果
cat /sys/devices/system/node/node2/hugepages/hugepages-1048576kB/nr_hugepages
0

1G 页分配失败了,原因往下看,一句话概括是 kernel 拒绝将 1G 页面放到 ZONE_MOVABLE 里进行管理。

为什么同样的方式不能开启 1G 大页?

这里先介绍一个背景,linux 里大页通常由两种,一种是 2M 大页,另一种是 1G 大页。1G 大页在理论上是可以迁移的,但是实际上是不可以迁移的。
不可迁移的原因是,当系统运行了一段时间后,系统内存已经碎了,很难找到一个空闲的 1G 大页将内存页里的数据搬运过去。因此,内核认为 1G 大页是不可以迁移的,不把 1G 大页放在 ZONE_MOVABLE 里进行管理。这也是造成照葫芦画瓢失败的原因。

如何在 PMEM 上分配 1G 大页?

当前操作系统(RHEL Family)环境下,很多因素会导致 pmem 会被自动 online 到 ZONE_MOVABLE。这也是我们为什么按照 2M 页方式开启 1G 页的方式失败的原因。

可能得原因有,daxtctl 工具本身,system udev 规则 或者 auto_online_blocks 。这三个因素,每一个都有可能导致 pmem online 到 ZONE_MOVABLE 上,进而导致分配失败

1、禁用 auto_online_blocks

cat /sys/devices/system/memory/auto_online_blocks
offline

2、修改系统 udev 规则

注释掉 Memory hotadd request 部分

vim /usr/lib/udev/rules.d/40-redhat.rules

# Memory hotadd request
# SUBSYSTEM!="memory", GOTO="memory_hotplug_end"
# ACTION!="add", GOTO="memory_hotplug_end"
# CONST{arch}=="s390*", GOTO="memory_hotplug_end"
# CONST{arch}=="ppc64*", GOTO="memory_hotplug_end"


# ENV{.state}="online"
# CONST{virt}=="none", ENV{.state}="online_movable"
# ATTR{state}=="offline", ATTR{state}="$env{.state}"


# LABEL="memory_hotplug_end"

3、daxctl 配置 !ZONE_MOVABLE

daxctl reconfigure-device dax0.0 --mode=system-ram --no-movable

经过上诉几个步骤,现在可以正常开启 1G 大页了。

Reference

1、man daxctl reconfigure-device movable
2、Memory Hot(Un)Plug Docs in Linux Kernel
3、Linux Kernel中AEP的现状和发展
4、How To Extend Volatile System Memory (RAM) using Persistent Memory on Linux – Steve Scargall