由 Intel AI 实际日工作组和第四范式发动的“英特尔 AI 实际日第 31 期 &AI 利用与异构内存编程挑战赛总动员”线上研讨会将于 6 月 10 日早晨开播。
届时,来自英特尔的分享嘉宾胡风华是傲腾事业部云软件架构师,将对傲腾 PMDK 编程技术进行简略介绍,并探讨在人工智能畛域的利用前景。
傲腾长久内存自 2019 年正式推出以来,曾经在在泛滥畛域展现出不凡实力,取得了宽泛赞美。特地是在人工智能方面,傲腾曾经胜利地利用在许多互联网公司的人工智能要害业务。
傲腾长久内存是如何为数据赋能,减速利用落地,本次特邀胡风华撰写详解长久内存编程技术。
01 傲腾长久内存及其应用模式
英特尔®傲腾™长久内存以翻新的内存技术从新定义了传统存储架构,将高性价比的大容量内存与数据持久性奇妙地联合在一起,以正当的价格提供大型长久内存层级。凭借在内存密集型工作负载,虚拟机密度和疾速存储容量方面的突破性性能程度,英特尔®傲腾™长久内存 (Intel® Optane™PMem) 可减速 IT 转型,以反对数据时代对算力的需要。
全新的 PMem 200 系列与第三代英特尔®至强®可扩大处理器 (Ice Lake, ICX) 搭配,入门级 PMem 系列与第二代英特尔®至强®可扩大处理器 (Cascade Lake, CLX) 搭配,与针对数据库,数据分析和虚拟化等基础设施等工作负载打造的软件生态系统放弃兼容,有助于更加无效地开掘数据的潜在价值。开发人员能够利用行业标准的长久内存编程模式,构建更简略,更弱小的利用,确保对数据中心的投资可能适应将来的需要。
长久内存产品可通过不同的办法应用,有些用法对利用来说是通明的。例如,所有长久内存产品都反对存储接口和标准文件 API,就像固态盘 (Solid State Disk, SSD) 一样;或者将长久内存配置成内存模式,零碎的长久内存的应用形式和零碎内存一样。通过这两种形式应用长久内存非常简单间接,咱们不须要对利用做任何更改就可应用,用户除了感触到性能的大幅晋升以外,甚至感触不到它们的存在。
但这两种形式也都有各自的弱点,对于第一种形式,因为基本上依然沿用过来的软件栈,无奈齐全施展傲腾长久内存的性能劣势;而对于第二种形式,尽管能取得大容量的内存,然而在拜访提早性能方面与内存相比仍有差距,并不能很好地应答对内存提早要求较高的场景,另外它也无奈对数据进行长久化。
要充分发挥傲腾长久内存在性能和长久化方面的弱小劣势,咱们引入了 AppDirect 模式。在这种模式下,利用能够从用户空间以相似内存的形式间接拜访长久内存,岂但可能齐全施展长久内存的性能劣势,并对数据进行就地长久化。这种模式须要用户对利用做出大量批改。
02 长久内存的特色
每项新技术的衰亡总会引发新的思考,长久内存也不例外。构建与开发解决方案时,请思考长久内存的以下特色:
- 长久内存的性能(吞吐量、提早和带宽)远高于 NAND,然而稍低于 DRAM。
- 不同于 NAND,长久内存很耐用。其耐用性通常比 NAND 高出多个数量级,能够超过服务器的生命周期。
- 长久内存模块的容量远大于 DRAM 模块,并且能够共享雷同的内存通道。反对长久内存的利用可原地更新数据,无需对数据进行序列化 / 反序列化解决。
- 长久内存反对字节寻址(相似于内存)。利用能够只更新所需的数据,不会产生任何读取 - 批改 - 写入(read-modify-write,RMW)开销。
- 数据与 CPU 高速缓存保持一致。长久内存可提供间接内存拜访 (direct memory access, DMA) 和近程间接内存拜访
(remote direct memory access, RDMA) 操作。 - 写入长久内存的数据不会在断电后失落。
- 权限查看实现后,能够间接从用户空间拜访长久内存上的数据。数据拜访不通过任何内核代码、文件系统页面缓存 (page cache) 或中断。
- 长久内存上的数据可立刻应用,也就是说:
o 零碎通电后即可应用数据。
o 利用不须要花工夫来预热高速缓存。
o 它们可在内存映射后立刻拜访数据。
- 长久内存上的数据不占用 DRAM 空间,除非利用将数据复制到 DRAM,以便更快地拜访数据。
- 写入长久内存模块的数据位于零碎本地。利用负责在不同零碎之间复制数据。
利用开发人员通常会思考内存驻留(memory-resident)数据结构和存储驻留(storage-resident)数据结构。就数据中心利用而言,开发人员要审慎地在存储中保持一致的数据结构,即便零碎解体时也不例外。
这个问题通常能够应用日志技巧(如预写日志)来解决,先将更改写入日志,而后再将其刷新到长久存储中。如果数据批改过程中断,利用能够借助日志中的信息,在重启时实现复原操作。这样的技巧已存在多年;但正确的施行办法开发难度很大,保护起来也很耗时。开发人员通常要依赖于数据库、编程库和古代文件系统的组合来提供一致性。
即便如此,最终还是要利用开发人员设计一种策略,在运行时和从利用和零碎解体中复原零碎时确保存储中数据结构的一致性。
03 SNIA NVM 编程模型
长久内存能够被应用程序间接拜访,并将数据执行就地长久化,因而能够让操作系统反对一种全新的编程模型,在提供媲美内存的高性能的同时,像非易失性存储设备一样长久存储数据。
对开发人员而言侥幸的是,在第一代长久内存还处于开发阶段时,Microsoft Windows 和 Linux 设计师、架构师和开发人员已与存储网络工业协会(SNIA)单干定义了一个长久内存编程通用编程模型 SNIA NVM 编程模型,如图 1 所示。
▲图 1 SNIA NVM 编程模型
长久内存用作块存储
操作系统可能检测是否存在长久内存模块,并将设施驱动程序加载到操作系统的 I/O 子系统中,如图 1 左半局部所示。非易失性双列直插式内存模块(NVDIMM)驱动程序具备两项重要性能。
首先,它为系统管理员提供了治理程序接口,用于配置和监控长久内存硬件的状态。其次,它具备相似于存储设备驱动程序的性能。NVDIMM 驱动程序将长久内存作为疾速块存储设备出现给应用程序和操作系统模块。
这意味着应用程序、文件系统、卷管理器和其余存储中间件层能够不经批改,像以后应用存储那样应用长久内存。
长久内存感知型文件系统
操作系统的另一项扩大是反对文件系统感知并针对长久内存进行优化。这类文件系统被称为长久内存感知型文件系统(PMem-Aware File System)。
以后长久内存感知文件系统包含 Linux ext4 和 XFS,以及 Microsoft Windows NTFS。如图 1 所示,这些文件系统既能够应用 I/O 子系统中的块驱动程序(如上文所述),也能够绕过 I/O 子系统,间接将长久内存用作可字节寻址加载 / 存储的内存,以最快、最短的门路拜访存储在长久内存中的数据。
除了革除了传统的 I/O 操作外,这条门路使得小数据块写入的执行速度比传统块存储设备更快,因为相比之下,传统块存储设备要求文件系统读取设施的原生块大小,批改块,而后将整个数据块写回到设施。这些长久内存感知型文件系统向应用程序提供相熟的标准文件 API,包含 open、close、read 和 write 零碎调用。这样应用程序能够持续应用相熟的文件 API,同时施展长久内存更高性能的劣势。
长久内存间接拜访
操作系统中的长久内存间接拜访个性(在 Linux 和 Windows 中被称为 Direct Access,DAX)应用操作系统所提供的内存映射文件接口,但却能充分利用长久内存的原生性能,既能存储数据,又能用作内存。长久内存能够原生地映射成应用程序内存,因而操作系统毋庸在易失性主内存中缓存文件。
为了应用 DAX,系统管理员须要在长久内存模块上创立一个文件系统,并将该文件系统挂载在操作系统的文件系统树中。对于 Linux 用户,长久内存设施将显示为 /dev/pmem* 设施非凡文件。若要显示长久内存物理设施,系统管理员能够应用 ndctl 和 ipmctl 程序。
04 长久内存开发套件 PMDK
如前文提到,应用程序能够通过应用内存映射文件的形式来间接拜访长久内存,然而这须要用户批改它们的应用程序。为了升高用户批改利用的老本,咱们引入了长久内存开发套件(PMDK)。咱们将介绍如何利用 PMDK 来批改利用,使得其高效治理驻留在长久内存中的可字节寻址的数据结构。
PMDK 库基于 SNIA NVM 编程模型构建。它们对该模型进行了不同水平的扩大,一些只是将操作系统提供的原语封装成简略易用的函数,另一些则提供了简单的数据结构和算法以便用于长久内存。这意味着你要负责决定哪个形象级别最适宜你的用例。
PMDK 通过多年的倒退,目前曾经蕴含了大量的开源库,如图 2 所示。这些库能帮忙利用开发人员和系统管理员简化长久内存设施的利用开发和治理。
PMDK 提供两种类型的库:
1)易失性库:实用于只想利用长久内存大容量这一劣势的用户和场景。
2)持久性库:实用于想实现故障安全长久内存算法的软件。
▲ 图 2 PMDK 相干的开发库
libmemkind
libmemkind 是构建在 jemalloc 之上的用户可扩大堆管理器,反对管制内存个性以及在不同类型的内存之间对堆进行分区。内存的类型由利用于虚拟地址范畴的操作系统内存策略进行定义。在没有用户扩大的状况下,memkind 反对的内存个性包含管制非一致性内存拜访(NUMA)和内存页大小个性。
jemalloc 非标准接口通过扩大,反对专门的类型通过 memkind 分区接口从操作系统申请虚拟内存。通过其余 memkind 接口,你能够管制和扩大内存分区个性和分配内存,同时抉择已启用的个性。借助 memkind 接口,你能够从反对 PMEM 类型的长久内存创立和管制基于文件反对的内存。
libmemcache
libvmemcache 是一种可嵌入式轻量级内存缓存解决方案,能够通过高效、可扩大的内存映射,充分利用大容量存储,例如反对 DAX 的长久内存。libvmemcache 具备本身的独特性:
- 基于区间的内存分配器可避免出现影响大多数内存数据库的碎片化问题,并反对缓存在大多数工作负载中实现极高的空间利用率。
- 缓冲的最近起码应用(LRU)算法将传统的 LRU 双向链表和非阻塞环形缓冲区相结合,可在古代多核 CPU 上实现较高的可扩展性。
- critnib 索引构造可提供高性能,同时十分节俭空间。缓存通过调优,可能以最佳形式解决大小绝对较大的值,最小为 256 字节,但 libvmemcache 最实用于预期数值大小超过 1 KB 的状况。
pmemkv
pmemkv 是为长久内存而优化设计的通用嵌入式本地键值存储。它易于应用,且附带许多不同的语言集成,包含 C、C++ 和 JavaScript。
该库还有面向不同存储引擎可插拔的后端插件。只管设计之初次要是用于反对持久性的应用程序场景,然而它也可用作易失性库。pmemkv 作为独自的我的项目创立,不仅为 PMDK 中的一套库提供云原生反对,还 提 供 面 向 持 久 内 存 构 建 的 键 值 API。pmemkv 开发人员的次要指标之一是为开源社区创立一个敌对的环境,反对他们在 PMDK 的帮忙下开发新引擎,并将它与其余编程语言集成。
pmemkv API 与大多数键值数据库相似在底层,它实现了多种存储引擎。这些存储引擎都具备杰出的灵活性和功能性。每种引擎都具备不同的性能特点,用于解决不同的问题。因而,每种引擎提供的性能各不相同,能够通过以下个性来形容:
- 长久:长久引擎确保批改可能失去保留,而且是断电平安的,而易失性引擎仅在应用程序生命周期内保留其内容。
- 并发:并发引擎确保某些办法(如 get()、put()、remove())是线程平安的。
- 键的排序:“排序”(sorted)引擎提供范畴查询方法(如 get_above())。pmemkv
与其余键值数据库的不同之处在于,它反对间接拜访数据。这意味着从长久内存中读取数据不须要复制到 DRAM 中。
间接拜访数据能够显著放慢应用程序的速度。在程序仅对数据库中存储的局部数据感兴趣时,这种劣势最为显著。在传统办法中,须要将所有数据复制到某个缓冲区中,而后将其返回给应用程序。借助 pmemkv,咱们为应用程序提供间接指针,应用程序仅读取所需的数据即可。
凭借其模块化设计、灵便的引擎 API 以及与许多常见云编程语言的集成,pmemkv 曾经成为许多云原生软件开发人员的首选。作为一种开源轻量级库,它能够轻松集成到现有应用程序中,并立刻施展长久内存的劣势;或者以此为根底针对特定的利用需要进行开发。
libpmemobj
libpmemobj 是一种提供事务对象存储的 C 库,可为长久内存编程提供动态内存分配器、事务和惯例性能。libpmemobj 库为须要事务和长久内存治理的应用程序提供了事务性对象,该对象以间接拜访(DAX)的形式存储在长久内存中。该库能够解决在长久内存编程时遇到的许多常见的算法和数据问题。
libpmemobj 反对应用程序在长久内存感知型文件系统上内存映射文件,提供间接加载 / 存储操作,而无须从块存储设备中对块进行分页。它能够绕过内核,防止上下文切换和中断,并反对应用程序在可字节寻址的长久内存中间接读写。
libpmemobj 库提供便捷的 API,用于轻松治理内存池的创立和拜访,防止间接映射和数据同步的复杂性。PMDK 还提供了 pmempool 程序,用于通过命令行来治理内存池。对于长久内存,能够应用 pmemobj_alloc()、pmemobj_reserve()或 pmemobj_ xreserve() 为长期对象保留内存,其应用办法与 malloc() 雷同。
libpmemobj 提供以下 三组 API:原子操作 API,保留 / 公布 API,事务 API,能够应用它们来实现数据的长久化。这些 API 都提供了故障安全原子性和一致性,可缩小创立应用程序时的谬误,同时确保数据的完整性。
Libpmemobj-cpp
libpmemobj 库面向底层系统软件开发人员和语言创立人员,提供了分配器、事务以及主动操作对象的办法。然而因为它不会批改编译器,导致它的 API 简短,且蕴含大量的宏。为了简化长久内存编程,缩小谬误,英特尔创立了针对 libpmemobj 的高级语言绑定,并将其增加至 PMDK。其中 C ++ 语言绑定是 libpmemobj-cpp,也称 libpmemobj++,是一种 C++ 仅头文件(header-only)库,能够应用 C ++ 的元编程个性,为 libpmemobj 提供更简略且更不易出错的接口。
它通过重复使用 C++ 程序员相熟的概念(如智能指针和闭包事务),提供了便捷的 API 来批改构造体和类,而只需对函数进行轻微改变,从而反对疾速开发长久内存应用程序。该库还附带兼容 STL 的定制数据结构和容器,因而应用程序开发人员毋庸从新为长久内存开发根本算法。
Libpmem
libpmem 是一种低级 C 库,可针对操作系统出现的原语提供根本形象性能。它能够自动检测平台中的性能,抉择适合的持久性语义以及面向长久内存优化的内存传输(memcpy())办法。大多数应用程序都至多须要应用这个库的一部分。
libpmem 负责解决与长久内存相干的 CPU 指令,以最佳形式将数据复制到长久内存以及文件映射。
libpmem 库蕴含一些用于内存映射文件的便捷函数。应用这些函数代替操作系统提供的内存映射函数,有如下长处:
- libpmem 能够保障操作系统映射调用的正确参数。
- libpmem 能够检测映射是否为长久内存以及应用 CPU 指令间接刷新是否平安。
- libpmem 也提供多个接口反对以最佳形式复制或清零长久内存区域以对数据进行长久化。
程序员如果只想齐全原始地拜访长久内存并且毋庸库提供分配器或事务性能,那么可能想将 libpmem 用作开发的根底。
对于大多数程序员而言,libpmem 十分底层,能够取得最大的编程灵活性,然而由此带来的编码和调试的代价绝对较高,如果不是必须,应该思考应用更加下层的库来进步开发效率,升高调试老本。
05 长久内存编程资源
英特尔®傲腾™长久内存介绍:
https://www.intel.cn/content/www/cn/zh/products/memory-storage/optane-dc-persistent-memory.html
SNIA NVM 编程模型标准:
https://www.snia.org/tech_activities/standards/curr_standards/npm
PMDK 官方网站:
https://pmem.io/
书籍:长久内存编程中文版
https://item.jd.com/13201774.html
PMDK:
https://github.com/pmem/pmdk
libmemkind:
http://memkind.github.io/memkind/
libvmemcache:
https://github.com/pmem/vmemcache
pmemkv:
https://github.com/pmem/pmemkv
libpmemobj-cpp:
https://github.com/pmem/libpmemobj-cpp
本文作者:胡风华 /Cloud Software Architect
胡风华,英特尔傲腾事业部云软件架构师,致力于摸索长久内存在云计算,大数据、人工智能和物联网等畛域的利用翻新。曾在阿里巴巴团体和 EMC 中国研发核心负责软件架构师和软件工程经理, 在文件系统,分布式存储系统,云计算和大数据等畛域有超过 15 年的工作教训。
6 月 10 日晚 19:30-21:00
胡风华老师将做客线上研讨会
英特尔 AI 实际日第 31 期 -AI 利用与异构内存编程挑战赛总动员
研讨会对傲腾 PMDK 编程技术进行简略介绍,并探讨在人工智能畛域的利用前景。研讨会同时重磅官宣 AI 利用与异构内存编程挑战赛,赛事官网:https://opensource.4paradigm….。
通过此次较量,你将会对人工智能如何在异构内存架构上受害有全新的意识,步入技术新境界。