极客时间已完结课程限时免费阅读

40 | Redis的下一步:基于NVM内存的实践

40 | Redis的下一步:基于NVM内存的实践-极客时间

40 | Redis的下一步:基于NVM内存的实践

讲述:蒋德钧

时长12:00大小10.96M

你好,我是蒋德钧。
今天这节课是咱们课程的最后一节课了,我们来聊聊 Redis 的下一步发展。
这几年呢,新型非易失存储(Non-Volatile Memory,NVM)器件发展得非常快。NVM 器件具有容量大、性能快、能持久化保存数据的特性,这些刚好就是 Redis 追求的目标。同时,NVM 器件像 DRAM 一样,可以让软件以字节粒度进行寻址访问,所以,在实际应用中,NVM 可以作为内存来使用,我们称为 NVM 内存。
你肯定会想到,Redis 作为内存键值数据库,如果能和 NVM 内存结合起来使用,就可以充分享受到这些特性。我认为,Redis 发展的下一步,就可以基于 NVM 内存来实现大容量实例,或者是实现快速持久化数据和恢复。这节课,我就带你了解下这个新趋势。
接下来,我们先来学习下 NVM 内存的特性,以及软件使用 NVM 内存的两种模式。在不同的使用模式下,软件能用到的 NVM 特性是不一样的,所以,掌握这部分知识,可以帮助我们更好地根据业务需求选择适合的模式。

NVM 内存的特性与使用模式

Redis 是基于 DRAM 内存的键值数据库,而跟传统的 DRAM 内存相比,NVM 有三个显著的特点。
首先,NVM 内存最大的优势是可以直接持久化保存数据。也就是说,数据保存在 NVM 内存上后,即使发生了宕机或是掉电,数据仍然存在 NVM 内存上。但如果数据是保存在 DRAM 上,那么,掉电后数据就会丢失。
其次,NVM 内存的访问速度接近 DRAM 的速度。我实际测试过 NVM 内存的访问速度,结果显示,它的读延迟大约是 200~300ns,而写延迟大约是 100ns。在读写带宽方面,单根 NVM 内存条的写带宽大约是 1~2GB/s,而读带宽约是 5~6GB/s。当软件系统把数据保存在 NVM 内存上时,系统仍然可以快速地存取数据。
最后,NVM 内存的容量很大。这是因为,NVM 器件的密度大,单个 NVM 的存储单元可以保存更多数据。例如,单根 NVM 内存条就能达到 128GB 的容量,最大可以达到 512GB,而单根 DRAM 内存条通常是 16GB 或 32GB。所以,我们可以很轻松地用 NVM 内存构建 TB 级别的内存。
总结来说,NVM 内存的特点可以用三句话概括:
能持久化保存数据;
读写速度和 DRAM 接近;
容量大。
现在,业界已经有了实际的 NVM 内存产品,就是 Intel 在 2019 年 4 月份时推出的 Optane AEP 内存条(简称 AEP 内存)。我们在应用 AEP 内存时,需要注意的是,AEP 内存给软件提供了两种使用模式,分别对应着使用了 NVM 的容量大和持久化保存数据两个特性,我们来学习下这两种模式。
第一种是 Memory 模式。
这种模式是把 NVM 内存作为大容量内存来使用的,也就是说,只使用 NVM 容量大和性能高的特性,没有启用数据持久化的功能。
例如,我们可以在一台服务器上安装 6 根 NVM 内存条,每根 512GB,这样我们就可以在单台服务器上获得 3TB 的内存容量了。
在 Memory 模式下,服务器上仍然需要配置 DRAM 内存,但是,DRAM 内存是被 CPU 用作 AEP 内存的缓存,DRAM 的空间对应用软件不可见。换句话说,软件系统能使用到的内存空间,就是 AEP 内存条的空间容量
第二种是 App Direct 模式。
这种模式启用了 NVM 持久化数据的功能。在这种模式下,应用软件把数据写到 AEP 内存上时,数据就直接持久化保存下来了。所以,使用了 App Direct 模式的 AEP 内存,也叫做持久化内存(Persistent Memory,PM)。
现在呢,我们知道了 AEP 内存的两种使用模式,那 Redis 是怎么用的呢?我来给你具体解释一下。

基于 NVM 内存的 Redis 实践

当 AEP 内存使用 Memory 模式时,应用软件就可以利用它的大容量特性来保存大量数据,Redis 也就可以给上层业务应用提供大容量的实例了。而且,在 Memory 模式下,Redis 可以像在 DRAM 内存上运行一样,直接在 AEP 内存上运行,不用修改代码。
不过,有个地方需要注意下:在 Memory 模式下,AEP 内存的访问延迟会比 DRAM 高一点。我刚刚提到过,NVM 的读延迟大约是 200~300ns,而写延迟大约是 100ns。所以,在 Memory 模式下运行 Redis 实例,实例读性能会有所降低,我们就需要在保存大量数据和读性能较慢两者之间做个取舍。
那么,当我们使用 App Direct 模式,把 AEP 内存用作 PM 时,Redis 又该如何利用 PM 快速持久化数据的特性呢?这就和 Redis 的数据可靠性保证需求和现有机制有关了,我们来具体分析下。
为了保证数据可靠性,Redis 设计了 RDB 和 AOF 两种机制,把数据持久化保存到硬盘上。
但是,无论是 RDB 还是 AOF,都需要把数据或命令操作以文件的形式写到硬盘上。对于 RDB 来说,虽然 Redis 实例可以通过子进程生成 RDB 文件,但是,实例主线程 fork 子进程时,仍然会阻塞主线程。而且,RDB 文件的生成需要经过文件系统,文件本身会有一定的操作开销。
对于 AOF 日志来说,虽然 Redis 提供了 always、everysec 和 no 三个选项,其中,always 选项以 fsync 的方式落盘保存数据,虽然保证了数据的可靠性,但是面临性能损失的风险。everysec 选项避免了每个操作都要实时落盘,改为后台每秒定期落盘。在这种情况下,Redis 的写性能得到了改善,但是,应用会面临秒级数据丢失的风险。
此外,当我们使用 RDB 文件或 AOF 文件对 Redis 进行恢复时,需要把 RDB 文件加载到内存中,或者是回放 AOF 中的日志操作。这个恢复过程的效率受到 RDB 文件大小和 AOF 文件中的日志操作多少的影响。
所以,在前面的课程里,我也经常提醒你,不要让单个 Redis 实例过大,否则会导致 RDB 文件过大。在主从集群应用中,过大的 RDB 文件就会导致低效的主从同步。
我们先简单小结下现在 Redis 在涉及持久化操作时的问题:
RDB 文件创建时的 fork 操作会阻塞主线程;
AOF 文件记录日志时,需要在数据可靠性和写性能之间取得平衡;
使用 RDB 或 AOF 恢复数据时,恢复效率受 RDB 和 AOF 大小的限制。
但是,如果我们使用持久化内存,就可以充分利用 PM 快速持久化的特点,来避免 RDB 和 AOF 的操作。因为 PM 支持内存访问,而 Redis 的操作都是内存操作,那么,我们就可以把 Redis 直接运行在 PM 上。同时,数据本身就可以在 PM 上持久化保存了,我们就不再需要额外的 RDB 或 AOF 日志机制来保证数据可靠性了。
那么,当使用 PM 来支持 Redis 的持久化操作时,我们具体该如何实现呢?
我先介绍下 PM 的使用方法。
当服务器中部署了 PM 后,我们可以在操作系统的 /dev 目录下看到一个 PM 设备,如下所示:
/dev/pmem0
然后,我们需要使用 ext4-dax 文件系统来格式化这个设备:
mkfs.ext4 /dev/pmem0
接着,我们把这个格式化好的设备,挂载到服务器上的一个目录下:
mount -o dax /dev/pmem0 /mnt/pmem0
此时,我们就可以在这个目录下创建文件了。创建好了以后,再把这些文件通过内存映射(mmap)的方式映射到 Redis 的进程空间。这样一来,我们就可以把 Redis 接收到的数据直接保存到映射的内存空间上了,而这块内存空间是由 PM 提供的。所以,数据写入这块空间时,就可以直接被持久化保存了。
而且,如果要修改或删除数据,PM 本身也支持以字节粒度进行数据访问,所以,Redis 可以直接在 PM 上修改或删除数据。
如果发生了实例故障,Redis 宕机了,因为数据本身已经持久化保存在 PM 上了,所以我们可以直接使用 PM 上的数据进行实例恢复,而不用再像现在的 Redis 那样,通过加载 RDB 文件或是重放 AOF 日志操作来恢复了,可以实现快速的故障恢复。
当然,因为 PM 的读写速度比 DRAM 慢,所以,如果使用 PM 来运行 Redis,需要评估下 PM 提供的访问延迟和访问带宽,是否能满足业务层的需求
我给你举个例子,带你看下如何评估 PM 带宽对 Redis 业务的支撑。
假设业务层需要支持 1 百万 QPS,平均每个请求的大小是 2KB,那么,就需要机器能支持 2GB/s 的带宽(1 百万请求操作每秒 * 2KB 每请求 = 2GB/s)。如果这些请求正好是写操作的话,那么,单根 PM 的写带宽可能不太够用了。
这个时候,我们就可以在一台服务器上使用多根 PM 内存条,来支撑高带宽的需求。当然,我们也可以使用切片集群,把数据分散保存到多个实例,分担访问压力。
好了,到这里,我们就掌握了用 PM 将 Redis 数据直接持久化保存在内存上的方法。现在,我们既可以在单个实例上使用大容量的 PM 保存更多的业务数据了,同时,也可以在实例故障后,直接使用 PM 上保存的数据进行故障恢复。

小结

这节课我向你介绍了 NVM 的三大特点:性能高、容量大、数据可以持久化保存。软件系统可以像访问传统 DRAM 内存一样,访问 NVM 内存。目前,Intel 已经推出了 NVM 内存产品 Optane AEP。
这款 NVM 内存产品给软件提供了两种使用模式,分别是 Memory 模式和 App Direct 模式。在 Memory 模式时,Redis 可以利用 NVM 容量大的特点,实现大容量实例,保存更多数据。在使用 App Direct 模式时,Redis 可以直接在持久化内存上进行数据读写,在这种情况下,Redis 不用再使用 RDB 或 AOF 文件了,数据在机器掉电后也不会丢失。而且,实例可以直接使用持久化内存上的数据进行恢复,恢复速度特别快。
NVM 内存是近年来存储设备领域中一个非常大的变化,它既能持久化保存数据,还能像内存一样快速访问,这必然会给当前基于 DRAM 和硬盘的系统软件优化带来新的机遇。现在,很多互联网大厂已经开始使用 NVM 内存了,希望你能够关注这个重要趋势,为未来的发展做好准备。

每课一问

按照惯例,我给你提个小问题,你觉得有了持久化内存后,还需要 Redis 主从集群吗?
欢迎在留言区写下你的思考和答案,我们一起交流讨论。如果你觉得今天的内容对你有所帮助,也欢迎你分享给你的朋友或同事。
分享给需要的人,Ta购买本课程,你将得20
生成海报并分享

赞 36

提建议

上一篇
39 | Redis 6.0的新特性:多线程、客户端缓存与安全
下一篇
41 | 第35~40讲课后思考题答案及常见问题答疑
unpreview
 写留言

精选留言(25)

  • Kaito
    2020-11-25
    有了持久化内存,是否还需要 Redis 主从集群? 肯定还是需要主从集群的。持久化内存只能解决存储容量和数据恢复问题,关注点在于单个实例。 而 Redis 主从集群,既可以提升集群的访问性能,还能提高集群的可靠性。 例如部署多个从节点,采用读写分离的方式,可以分担单个实例的请求压力,提升集群的访问性能。而且当主节点故障时,可以提升从节点为新的主节点,降低故障对应用的影响。 两者属于不同维度的东西,互不影响。
    展开
    共 5 条评论
    106
  • Mr.Brooks
    2020-12-04
    使用NVM,没有了RDB,主从复制对于新添加的机器,是怎么实现的呢

    作者回复: 这是个好问题。 增加从节点时,需要把全库数据拷贝到从节点上。我自己现在考虑的有两种方法:一种还是用写前日志,日志拷贝到从节点进行回放,但是这会带来双写的问题。另一种是,主节点在NVM上做快照,但是不写文件,从节点上直接从主节点的NVM上通过远程内存拷贝来实现复制,这个需要基于RDMA来做。

    共 2 条评论
    26
  • u
    2020-11-27
    老师,比较好奇应用程序是如何基于持久化内存来恢复自身的状态的,还是说应用程序本身也作为持久化的一部分,在重启后就存在于内存中?

    作者回复: 这个问题很好。目前,应用程序是把本来要保存到磁盘上的数据保存到持久化内存上了,但是应用程序运行时的堆和栈还是在DRAM上,进程重启这些运行时信息就丢了。 所以,如果想把应用程序本身的运行时状态,例如堆栈等,也保存到持久化内存上,这个需要对操作系统的内核做修改。目前还没有成熟的方案。

    17
  • 好好学习
    2021-01-15
    终于学完了。 我真棒!
    共 1 条评论
    15
  • Lemon
    2020-11-25
    肯定还是需要的,两者是互补的。 NVM 给了数据存储方面的新方案,但目前用作 PM 的读写速度比 DRAM 慢,不使用主从集群仍会有明显的访问瓶颈。【过大的实例在主从同步时会有影响(缓存、带宽)】 而集群是为了高可用,分散了数据的访问和存储,便于拓展与维护。对于单实例而言,即便单实例恢复的再快,挂了对业务仍会有影响。 感觉 NVM 内存用作 PM 有点像第 28 将的 Pika,如果把 SSD 换为 NVM ,岂不是都再内存中操作?是否可以解决 Pika 操作慢的缺点?
    展开

    作者回复: 回答的很好。 而且对NVM使用的思考非常赞。NVM的读写延迟(几百ns级别)还是要低于SSD的(几十到几百us级别),所以使用NVM替换SSD是可以解决Pika操作慢的问题。 不过,NVM的每GB成本还是要高于SSD的,这个在实际应用中要考虑。

    共 2 条评论
    8
  • 宙斯
    2021-01-30
    需要。主从集群 1读写分离,降低实例压力 2数据冗余,防止介质损坏数据丢失

    作者回复: 对主从集群的作用理解到位。

    7
  • 李梦嘉
    2020-12-04
    老师,请问有AEP方案redis的最佳实践么,最近在调研这方面

    作者回复: Intel有在推基于AEP的Redis,可以看下 https://www.intel.com/content/dam/www/public/us/en/documents/solution-briefs/redis-enterprise-brief.pdf 另外,github上有基于PMem的Redis实现,是基于Redis 4.0实现,有些旧了,不过可以作为一个参考。 https://github.com/pmem/pmem-redis 另外,阿里云上的Tair有基于AEP做扩展,参考 https://developer.aliyun.com/article/776609

    共 2 条评论
    7
  • yyl
    2020-11-25
    问题:有了持久化内存,是否还需要 Redis 主从集群? 解答:需要,主从集群解决的单点故障问题,而且还能起到一定的负载分担。而NVM解决的是数据丢失

    作者回复: 对主从集群作用的理解很到位 :)

    4
  • 写点啥呢
    2020-11-25
    请问蒋老师,Redis将PM用作内存模式的话,是否需要修改Redis代码。我理解内存模式是对程序透明的,虽然PM可以把数据持久化保存,但是如果Redis进程把它看做内存,如果希望进程启动能够自动回复,就会涉及到进程内存空间的恢复,OS里是没有这个功能的,是不是应该需要Redis来做个事情,才可以直接从PM保存的上一次数据中作为新进程的内存空间,而不再需要通过RDB或者AOF来做数据持久化?
    4
  • neohope
    2021-02-25
    老师好,关于mmap映射的问题,没看明白,有几点不清楚,还望帮忙解答: 1、将redis内存空间,用mmap映射到PM的ext系统文件后,保持的就是内存信息吧?那进程信息、线程信息、寄存器状态什么的,需要额外保持吗? 2、redis挂掉后,重新启动要如何做呢? 3、操作系统重启动后,再启动redis时,还能用这个持久化后的文件吗?要如何做呢? 4、用集群的时候,节点间复制要如何做呢? 感谢!
    展开
    2
  • Mr.蜜
    2020-12-21
    由于PM的读写速度存在差异,使用读写分离的主从集群,还是有必要,这样可以分担单实例的处理压力,提升redis整体的性能,所以使用主从集群还是非常有必要的。

    作者回复: 大流量情况下,单个实例的压力太大,从节点是可以用来分担读压力的。

    共 2 条评论
    1
  • 范闲
    2020-12-03
    主从集群仍旧需要。 单机失踪了持久化内存只能解决单机的存储容量和数据恢复问题。 主从集群可以提高访问速度,提高可靠性,做到HA。
    1
  • NULL
    2022-09-10 来自山东
    关于dram, nvm, ssd的区别, 可以看下Intel Optane AEP的介绍, 在1:18秒处 https://www.intel.cn/content/www/cn/zh/architecture-and-technology/optane-dc-persistent-memory.html
  • piboye
    2022-02-19
    gpu 内存可以加速redis性能吗?
  • piboye
    2022-02-14
    nvm后还要记内存日志更好,一些操作执行到中间步骤的时候失败了,重启之后要有办法回滚。
  • piboye
    2022-02-12
    解决主从一致性的问题,redis就可以当个分布式db了
  • 彭文达
    2021-10-12
    完结撒花
  • 花儿少年
    2021-10-09
    NVM 也是有些缺陷的,也可能会导致数据不一致。例如,在redis的新增一个数据节点,那么会有两步操作,1、分配内存,写入数据;2、将此内存地址的指针指向redis管理;而这两步我们知道在很多情况下都可能是乱序执行的,如果第二步先执行,此时机器crash了,redis就指向了一个无效地址。
  • Heaven
    2021-09-08
    单机版的Redis必然存在着实例服务器宕机的问题,那么Redis主从集群必然有存在的需求 不过有了NVM,使用K8S直接管理也是可以的,毕竟绑定了固定的volume,也可以保证持久化和自动重启
  • BertGeek
    2021-06-07
    从高可用角度考虑,主从集群还是非常必要, NVM只是解决读写性能,可持久存储,只要是硬件也需要考虑坏的可能。 Redis数据需要备份,还是要做足工作的