Redis 核心技术与实战
蒋德钧
中科院计算所副研究员
81696 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 53 讲
开篇词 (1讲)
实践篇 (28讲)
Redis 核心技术与实战
15
15
1.0x
00:00/00:00
登录|注册

05 | 内存快照:宕机后,Redis如何实现快速恢复?

增量快照
连续快照
Copy-On-Write技术
快照时数据修改问题
bgsave命令
save命令
RDB文件
内存快照类比
场景分析
混合使用RDB和AOF的建议
局限性
内存快照的优势
优势
方法介绍
快照频率
数据修改
全量快照
概念
AOF方法的缺点
Redis持久化方法总结
每课一问
小结
混合使用AOF和内存快照
内存快照
介绍
Redis内存快照持久化方法

该思维导图由 AI 生成,仅供参考

你好,我是蒋德钧。
上节课,我们学习了 Redis 避免数据丢失的 AOF 方法。这个方法的好处,是每次执行只需要记录操作命令,需要持久化的数据量不大。一般而言,只要你采用的不是 always 的持久化策略,就不会对性能造成太大影响。
但是,也正因为记录的是操作命令,而不是实际的数据,所以,用 AOF 方法进行故障恢复的时候,需要逐一把操作日志都执行一遍。如果操作日志非常多,Redis 就会恢复得很缓慢,影响到正常使用。这当然不是理想的结果。那么,还有没有既可以保证可靠性,还能在宕机时实现快速恢复的其他方法呢?
当然有了,这就是我们今天要一起学习的另一种持久化方法:内存快照所谓内存快照,就是指内存中的数据在某一个时刻的状态记录。这就类似于照片,当你给朋友拍照时,一张照片就能把朋友一瞬间的形象完全记下来。
对 Redis 来说,它实现类似照片记录效果的方式,就是把某一时刻的状态以文件的形式写到磁盘上,也就是快照。这样一来,即使宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。这个快照文件就称为 RDB 文件,其中,RDB 就是 Redis DataBase 的缩写。
和 AOF 相比,RDB 记录的是某一时刻的数据,并不是操作,所以,在做数据恢复时,我们可以直接把 RDB 文件读入内存,很快地完成恢复。听起来好像很不错,但内存快照也并不是最优选项。为什么这么说呢?
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Redis内存快照是一种快速恢复机制,以RDB文件形式记录内存中的数据状态,实现了快速恢复而不影响性能。全量快照为了保证数据可靠性,但可能影响性能,Redis提供了bgsave命令来在后台生成RDB文件,避免主线程阻塞。在执行快照时,数据可以被修改,但为了保证快照完整性,Redis使用写时复制技术,允许主线程同时对数据进行修改。增量快照记录修改的数据,避免全量快照的开销。Redis 4.0提出了混合使用AOF日志和内存快照的方法,享受RDB文件快速恢复的好处,又能以较小的开销做到尽量少丢数据。内存快照能快速恢复数据库,但频繁快照仍然是不太能接受的。混合使用RDB和AOF可以以较小的性能开销保证数据可靠性和性能。对于持久化选择问题,建议混合使用内存快照和AOF,或者只使用RDB,优先使用everysec的AOF配置选项。文章还提供了一个场景,让读者分析在该场景下使用RDB做持久化的风险。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Redis 核心技术与实战》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(132)

  • 最新
  • 精选
  • Devin
    置顶
    老师全文中都是使用的“主线程”而不是“主进程”,评论中大家有的用的是“主线程”有的是“主进程”。请问下老师为啥不是用的“主进程”?

    作者回复: Redis启动后本身是一个进程,它的主体工作(接收请求、服务请求读写数据)也是在这个进程中完成的,咱们有些同学称Redis为主进程是可以的。 同时,Redis这个进程属于单线程的进程,也就是说进程主体工作没有用多个线程来运行,所以我一般把它也称为主线程,突显它的单线程模式。 有的程序启动后,会在进程中启动多个线程来处理工作,这个时候我就不会称它为主线程了,因为没有一个线程是单独做主要工作的。 希望能解答了你的问题。

    2020-08-24
    8
    124
  • Kaito
    置顶
    2核CPU、4GB内存、500G磁盘,Redis实例占用2GB,写读比例为8:2,此时做RDB持久化,产生的风险主要在于 CPU资源 和 内存资源 这2方面: a、内存资源风险:Redis fork子进程做RDB持久化,由于写的比例为80%,那么在持久化过程中,“写实复制”会重新分配整个实例80%的内存副本,大约需要重新分配1.6GB内存空间,这样整个系统的内存使用接近饱和,如果此时父进程又有大量新key写入,很快机器内存就会被吃光,如果机器开启了Swap机制,那么Redis会有一部分数据被换到磁盘上,当Redis访问这部分在磁盘上的数据时,性能会急剧下降,已经达不到高性能的标准(可以理解为武功被废)。如果机器没有开启Swap,会直接触发OOM,父子进程会面临被系统kill掉的风险。 b、CPU资源风险:虽然子进程在做RDB持久化,但生成RDB快照过程会消耗大量的CPU资源,虽然Redis处理处理请求是单线程的,但Redis Server还有其他线程在后台工作,例如AOF每秒刷盘、异步关闭文件描述符这些操作。由于机器只有2核CPU,这也就意味着父进程占用了超过一半的CPU资源,此时子进程做RDB持久化,可能会产生CPU竞争,导致的结果就是父进程处理请求延迟增大,子进程生成RDB快照的时间也会变长,整个Redis Server性能下降。 c、另外,可以再延伸一下,老师的问题没有提到Redis进程是否绑定了CPU,如果绑定了CPU,那么子进程会继承父进程的CPU亲和性属性,子进程必然会与父进程争夺同一个CPU资源,整个Redis Server的性能必然会受到影响!所以如果Redis需要开启定时RDB和AOF重写,进程一定不要绑定CPU。

    作者回复: 除了考虑了内存风险,还考虑了CPU风险。赞!先置个顶 :D 关于绑核的操作,后面再和Kaito同学聊聊,绑核也有些值得探讨的地方的。

    2020-08-14
    117
    1029
  • Geek_Lin
    文章中写时复制那里,复制的是主线程修改之前的数据还是主线程修改之后的呢?

    作者回复: 子进程读到的是主线程修改前的数据。 我在文章中介绍写时复制时,说法上有点偏它能达到的效果了,可能让大家理解有误了,抱歉! 我再解释下,文章中说“这块数据就会被复制一份,生成该数据的副本”,这个操作在实际执行过程中,是子进程复制了主线程的页表,所以通过页表映射,能读到主线程的原始数据,而当有新数据写入或数据修改时,主线程会把新数据或修改后的数据写到一个新的物理内存地址上,并修改主线程自己的页表映射。所以,子进程读到的类似于原始数据的一个副本,而主线程也可以正常进行修改。 希望能解答你的疑惑。

    2020-08-16
    14
    88
  • 扩散性百万咸面包
    感觉老师这里是不是说的有点问题? 1.fork()本身应该是比较快的吧?因为COW的存在,只需要部分数据(局部变量)的复制。真正阻塞的是bgsave在持久化过程中写RDB的时候,因为同时要服务写请求,所以主线程要复制对应内存。 2.这个复制为什么不能让fork()出来的子线程去做呢?这样不就不阻塞主线程了吗?

    作者回复: 可以看下第10讲的答疑,有对COW的底层机制做了更加详细的介绍。 第5讲介绍COW时,有点偏于介绍COW的效果了。实际上,fork本身这个操作执行时,内核需要给子进程拷贝主线程的页表。如果主线程的内存大,页表也相应大,拷贝页表耗时长,会阻塞主线程。 bgsave保存RDB时,如果有写请求,主线程会把新数据写到新的物理地址,此时的阻塞会来自于主线程申请新内存空间以及复制原数据。 如果是子进程做复制,而主线程直接改数据的话,会有问题:1. 如果子进程还没有把一块数据写入RDB时,主线程就修改了数据,那么就快照完整性就被破坏了;2. 子进程复制数据时,也需要加锁,避免主线程同时修改,如果此时,主线程正好有写请求要处理,主线程同样会被阻塞。

    2020-08-29
    5
    40
  • yyl
    解答: 系统的QPS未知,两种情况吧: 1. QPS较低,不会有什么问题 2. QPS较高,首先由于写多读少,造成更多的写时拷贝,导致更多的内存占用。如果采用增量快照,需要增加额外的内存开销;再则,写RDB文件,OS会分配一些Cache用于磁盘写,进一步加剧内存资源的消耗。 由于频繁的写RDB文件,造成较大的磁盘IO开销,消耗CPU

    作者回复: 非常赞!考虑到了根据不同的QPS进行分析。 我再提一个维度,你可以考虑下,就是修改的键值对的范围,也就是说写操作是针对一小部分键值对,还是针对大部分键值对的。你觉得这个维度会有影响么?

    2020-08-15
    2
    21
  • 漫步oo0云端
    我想提一个傻问题,我作为初学者想问,如果redis服务挂了,备份有什么用?能恢复的前提不是服务还存活吗?难道服务挂了会自动拉起服务?自动还原吗?

    作者回复: 如果服务挂了,我们可以让Redis实例自动重启。此时,如果没有数据备份的话,再启动时,所有的数据都需要重新写入,这个过程会比较耗时。而如果有备份的话,Redis再启动后,可以直接读入备份数据,对于这些数据的读写操作就可以很快服务了。不知道有没有解答你的疑惑。 愿意提出来的问题都是好问题哈 :)

    2020-08-14
    19
    17
  • 老师,请教一下,bgsave命令只能是手动执行么?没配置中只看到了save,没有bgsave的配置

    作者回复: 可以自动执行。Redis配置文件中的save选项是用来配置bgsave的触发条件的,例如 save 60 10000 如果60s内有至少10000个键值对的修改,就会自动触发bgsave了。

    2020-08-29
    9
  • 小宇子2B
    做RDB期间是写时复制的 2GB的数据 80%都是写请求 也就是大概要复制出来1.6GB数据,加上本身数据2GB ,已经达到3.6GB,去掉操作系统本身的内存占用 机器所剩内存已经不多了 容易发生OOM

    作者回复: 分析的不错,这种情况下,内存的潜在压力风险比较大。 另外,Kaito同学还分析了CPU资源的风险,也可以看看。

    2020-08-14
    4
    8
  • 周翔在山麓(Xiang Zhou)
    这一讲真的很好, aof 相当于数据库的 binlog, rdb 相当于redo log. 知识互相映射, 加强了学习. 我又看了一遍mysql 的数据恢复机制. 同学们还记得吗?

    作者回复: 学习时把知识贯通起来理解是个好方法!

    2021-01-01
    5
    7
  • Spring4J
    由于修改操作占大部分比例,为了尽可能保证宕机时数据的完整性,快照的间隔就不能太长,而间隔太短又会带来很多的性能开销,所以对于这种特点的数据,不适合使用RDB的持久化方式

    作者回复: 不错,不错!可以再想想看,在问题里的云主机上,哪怕我们先不考虑快照频率问题,单就做一次快照本身,是否可能还会有其他问题?:)

    2020-08-14
    2
    2
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部