AEP 简介
AEP 是 Intel 推出的一种新型的非易失 Optane Memory 设备, 又被称作 Apache Pass, 所以一般习惯称作 AEP. 在这之前也有类似的设备称作 NVDIMM 或 PMEM, 目前 Linux 创建的 AEP 设备节点也是叫做 pmem(如 / dev/pmem0), 所以本文中 NVDIMM 或 PMEM 都指 AEP.
但是本文不是为了科普 AEP, 如果想了解 AEP 的一些基本知识, 可以参考以下几篇文章:
- NVDIMM Enabling in SUSE Linux Enterprise Part 1 NVDIMM Enabling in SUSE Linux Enterprise Part 2
- Persistent Memory Wiki
- DAX
目前 Linux Kernel 中主要把 PMEM 看成一个类似于磁盘的块设备, 所以可以在 PMEM 设备上创建文件系统, 使它看起来和一般的磁盘没什么区别. 但是设备的具体物理属性完全不一样, 比如读写的 latency,PMEM 可以达到和 DRAM 接近的程度, 磁盘当然是望尘莫及的. 所以, 这就带来一个问题, 众所周知, 一般在 Linux 上常见的文件系统, 比如 ext4,xfs 等, 都是给磁盘设计的, 都用到了 page cache 来缓存磁盘上的数据来提高性能.
但是, 对于 PMEM 设备来说, 它的访问延迟已经和内存接近了, 为什么还需要内存中的 page cache 呢? 所以, 目前 Linux Kernel 中对这一块最大的改进就是支持 DAX(Direct Access). 一句话解释 DAX, 就是 DAX bypass 了 page cache. 无论读写都是直接操作 PMEM 上的数据. DAX 需要在文件系统层面支持, 如果要使用 DAX, 那么需要在 mount 文件系统时传入 "-o dax" 参数, 比如:
/dev/pmem0 on /mnt type xfs (rw,relatime,seclabel,attr2,dax,inode64,noquota)
DAX 极大地提高了文件系统在 PMEM 设备上的性能, 但是还有一些问题没有解决, 比如: 1. 文件系统的 metadata 还是需要使用 page cache 或 buffer cache.
"-o dax"mount option 是对整个文件系统的, 不能做更细粒度的控制.
没有一个 API 来告诉应用访问的文件是不是可以 DAX 访问的.
虽然 DAX 还有这些问题, 但是目前 DAX 还是 Linux Kernel 中的主流使用方式.
PMEM 用作 NUMA node
既然 PMEM 就是 memory, 只是带宽和 latency 上差一点, 那么自然会想到能不能就把 PMEM 当做 memory 用呢? 答案当然是可以的. 目前支持 SRAT 或者 HMAT 的硬件, 都可以把 PMEM 识别为一个或多个 NUMA node.Dave Hansen 的这组 patch,Allow persistent memory to be used like normal RAM, 就是通过 memory hotplug 的方式把 PMEM 添加到 Linux 的 buddy allocator 里面. 新添加的 PMEM 会以一个或多个 NUMA node 的形式出现, Linux Kernel 就可以分配 PMEM 上的 memory, 这样和使用一般 DRAM 没什么区别. 目前看这组 patch 已经没有什么 blocking issues, 不出什么问题的话, 很快就会合并进入内核主线.
但是, 到这里只是解决了第一步的问题, 怎么把 PMEM"用好" 的问题还没有解决. 比如, 当内核分配内存时, 如果从 PMEM 上分配了 memory, 并且这块内存上的数据是被经常访问的, 那么由于物理特性上的差异, 一般应用都会体会到性能的下降. 那么怎么更明智的使用 PMEM 就是一个亟待解决的问题.
吴峰光的一组 patch,PMEM NUMA node and hotness accounting/migration, 来尝试解决这个问题.
这组 patch 主要提供了下面几个功能: 1. 隔离 DRAM 和 PMEM. 为 PMEM 单独构造了一个 zonelist, 这样一般的内存分配是不会分配到 PMEM 上的.
跟踪内存的冷热. 利用内核中已经有的 idle page tracking 功能 (目前主线内核只支持系统全局的 tracking), 在 per process 的粒度上跟踪内存的冷热. 3. 利用现有的 page reclaim, 在 reclaim 时将冷内存迁移到 PMEM 上(只能迁移匿名页). 4. 利用一个 userspace 的 daemon 和 idle page tracking, 来将热内存(在 PMEM 上的) 迁移到 DRAM 中.
这组 patch 发到 LKML 以后, 引来了很激烈的讨论, 主要集中在两个方面:
1. 为什么要单独构造一个 zonelist 把 PMEM 和 DRAM 分开?
其实在这块, 我们也遇到了相似的问题. 我们在某些项目要求做到控制每个进程使用的 DRAM 和 PMEM 的比例(比如 8:2), 但是目前的 NUMA API 做不到. 目前的 NUMA API 只能控制从哪个 node 分配, 但是不能控制比例, 比如 mbind(), 只能告诉进程这段 VMA 可以用哪些 node, 但是不能控制具体多少 memory 从哪个 node 来. 要想做到更细粒度的控制, 需要改造目前的 NUMA API. 而且目前 memory hierarchy 越来越复杂, 比如 device memory, 这都是目前的 NUMA API 所不能很好解决的.
2. 能不能把冷热内存迁移通用化?
冷热内存迁移这个方向是没有问题的, 问题在于目前 patch 中的处理太过于 PMEM specific 了. 内核中的 NUMA balancing 是把 "热" 内存迁移到最近的 NUMA node 来提高性能. 但是却没有对 "冷" 内存的处理. 所以能不能实现一种更通用的 NUMA rebalancing? 比如, 在 reclaim 时候, 不是直接 reclaim 内存, 而是把内存迁移到一个远端的, 或者空闲的, 或者低速的 NUMA node, 类似于 NUMA balancing 所做的, 只不过是往相反的方向.
笔者的一组 patch,Another Approach to Use PMEM as NUMA Node, 就体现了这种思路. 利用 Kernel 中已经很成熟的 memory reclaim 路径把 "冷" 内存迁移到 PMEM node 中, NUMA Balancing 访问到这个 page 的时候可以选择是否把这个页迁移回 DRAM, 相当于是一种比较粗粒度的 "热" 内存识别.
社区中还有一种更加激进的想法就是不区分 PMEM 和 DRAM, 在 memory reclaim 时候只管把 "冷" 内存迁移到最近的 remote node, 如果 target node 也有内存压力, 那就在 target node 上做同样的迁移. 但是这种方法有可能引入一个内存迁移 "环", 导致内存在 NUMA node 中间不停地迁移, 有可能引入 unbounded time 问题. 而且一旦 node 增多, 可能会迅速恶化问题.
在笔者看来, 在内存回收方面还有一个更可能立竿见影的方案就是把 PMEM 用作 swap 设备或者 swap 文件. 目前 swap 的最大问题就是传统磁盘的延迟问题, 很容易造成系统无响应, 这也是为什么有 zswap 这样的技术出现. PMEM 的低延迟特性完全可以消除 swap 的延迟问题. 在这个方面, 我们也正在做一些探索和实验.
PMEM 用作 RAM(DRAM 作为 Cache)
这个标题看起来有点歧义, 上面已经说了 PMEM 可以作为 NUMA node 使用, 这不已经是作为 RAM 了吗? 怎么这里还要说用作 RAM? 这就涉及到 AEP 的另一个用法了, 那就是所谓的 "memory mode". 当在 memory mode 时, DRAM 并不是和 PMEM 并列的, 而是变成了 PMEM 透明的 Cache,PMEM 就成了 DRAM. 这时候 PMEM 和 DRAM 的关系就变成了 DRAM 和 Cache 的关系. 而且, DRAM 是一个 direct mapped 的 Cache(这点很重要).
这时疑问就来了, 这样不是更没有什么可做的? 既不需要管理 NUMA, 也没有冷热内存的问题了, 热的自然就被 Cache 了. 是的, 但是这会引入另外一个问题, 就是 Cache 冲突的问题. 上面已经提到, 在这种情况下, DRAM 是一个 direct mapped 的 Cache, 就是在同样索引下只有一个 cache line 命中, 这样会带来比较严重的 Cache 冲突问题, 从而降低 Cache 的命中率, 带来性能问题. 对于这个问题的详细解释, 请参见这篇文章.
为了解决这个 Cache 冲突的问题, Dan Williams 提出了这组 patch,mm: Randomize free memory. 这组 patch 的想法很简单, 就是通过 randomize free area 的方式来降低 Cache 冲突. 目前这组 patch 已经合并入 - mm tree, 不出意外应该会在 5.1 时合并入内核主线. 但是这种配置的问题就是不够灵活, 需要在 BIOS 中配置, 一旦配置不可在运行时更改.
NVDIMM 专用文件系统
前面提到 PMEM 可以作为一个块设备部署文件系统, 但是现在支持的文件系统, 比如 ext4,xfs 等, 在设计时更多的考虑了怎样针对磁盘优化. 但是 PMEM 是性质完全不同的存储介质, 虽然经过一些改造, 这些传统的文件系统可以比较好的工作在 PMEM 上, 但是还是会有很多不适合 PMEM 的地方, 比如 metadata 还要经过 page cache 等. 所以, NVDIMM 专用文件系统就应用而生了.
NOVA
NOVA Filesystem 就是专门为 PMEM 设计的文件系统. 笔者对文件系统研究不深, 而且对 NOVA 也没有很深入的研究, 所以就不在这里班门弄斧了. 感兴趣的读者可以参考 NOVA 的 GitHub link.
之前, NOVA 曾发到 LKML 上, 但是好像社区里的 maintainer 们没有时间仔细 review 一个新的文件系统, 所以合入社区的努力暂时停止了, 但是还在 GitHub 上继续开发中.
ZUFS
ZUFS 是来自于 NetApp 的一个项目, ZUFS 的意思是 Zero-copy User Filesystem. 声称是实现了完全的 zero-copy, 甚至文件系统的 metadata 都是 zero-copy 的. ZUFS 主要是为了 PMEM 设计, 但是也可以支持传统的磁盘设备, 相当于是 FUSE 的 zero-copy 版本, 是对 FUSE 的性能的提升.
目前作者正在尝试将 ZUFS 的 kernel 部分 upstream, 据他说 RHEL 已经同意将 ZUFS 作为一个 module 加入 RHEL 8.
来源: https://yq.aliyun.com/articles/703891