都9102了,你还不懂Redis的持久化?

JAVA herman 329浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog,发送下载链接帮助你免费下载!
本博客日IP超过1800,PV 2600 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog,之前的微信号好友位已满,备注:返现
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领

都 9102 年了,你还在面试中通俗简单的回答,Redis 的持久化是 RDB 和 AOF!我随便扩展一点,你就露馅了!

你忽略的才叫知识

比如,Redis 的默认持久化方式是哪一种?

嗯,对不起,我不清楚。老师只是说 Redis 的持久化是 RDB 和 AOF,具体默认是谁?我忘了!

持久化后,是一个二进制文件的是哪一种方式?

嗯,我对这个不是很了解。我目前还只是在会用的阶段,后面我会加强学习去了解!

类似的问题我就不在列举了。多数人都是在使用,而没有认真的想过,为什么是这样?底层是如何实现的!

尴尬的面试

今天,时间关系,我就简单的说一下 RDB 和 AOF 持久化常见的面试题和应该注意的知识点。

Redis 生成 RDB 文件有两个命令。一个是 SAVE、另一个是 BGSAVE。两者的区别在于:SAVE 命令会阻塞 Redis 服务器进程,直到 RDB 文件创建完毕为止。在服务器进程阻塞期间,服务器是不能处理任何命令请求的;而 BGSAVE 命令不会阻塞服务器进程,因为是通过 fork 一个子进程,并让其去创建 RDB 文件,而服务器进程(父进程)继续则继续处理命令请求,当写完数据库状态后,新 RDB 文件就会原子地替换旧的 RDB 文件。

拓展面试题:如果在执行 BGSAVE 期间,客户端发送 SAVE、BGSAVE 或 BGREWRITEAOF 命令给服务端,服务端会如何处理呢?

答案是:在执行 BGSAVE 期间,上述三个命令都不会被执行。原因是:前两个会被直接拒绝,原因是为了避免父子进程同时执行两个 rdbSave 调用,防止产生竞争条件。而 BGREWRITEAOF 命令则是会被延迟到 BGSAVE 命令执行之后再执行。但如果是 BGREWRITEAOF 命令正在执行,此时客户端发送 BGSAVE 命令则会被拒绝。因为 BGREWRITEAOF 和 BGSAVE 都是由子进程执行的,所以在操作方面没有冲突的地方,不能同时执行的原因是性能上的考虑——并发出两个子进程,并且这两个子进程都会同时执行大量 io(磁盘写入)操作。

说完 RDB 文件的创建,我们在来说说 RDB 文件的加载。

Redis 的 RDB 持久化文件的载入是在服务器启动时自动执行的,所以 Redis 并没有用于载入的命令,并且在载入期间会阻塞主进程。

另外需要注意的是,只要没有开启 AOF 持久化功能,在启动时只要检测到有 RDB 文件,就会自动载入。

当服务器有开启 AOF 持久化功能时,服务器将会优先使用 AOF 文件来还原数据库状态。原因是 AOF 文件的更新频率通常比 RDB 文件的更新频率高。

RDB 持久化通过保存数据库状态来持久化。而 AOF 与之不同,它是通过保存对数据库的写命令来记录数据库状态。比如执行了 set key 业余草,Redis 就会将这条写命令保存到 AOF 文件中。在服务器下次启动时,就可以通过载入和执行 AOF 文件中保存的命令,来还原服务器关闭前的数据库状态了。总体流程和 RDB 持久化一样,都是创建一个 xxx 文件、在服务器下次启动时就载入这个文件来还原数据。

AOF 持久化功能的实现可以分为 3 个步骤:命令追加、文件写入、文件同步。命令追加很好理解,就是将写命令追加到 AOF 缓冲区的末尾。文件写入就是将缓冲区内容写到 AOF 文件,文件同步是将 AOF 文件保存到磁盘。

既然 AOF 持久化是通过保存写命令到文件的,那随着时间的推移,这个 AOF 文件记录的内容就越来越多,文件体积也就越来越大,对其进行数据还原的时间也就越来越久。

因此,Redis 提供了 AOF 文件重写功能。这个功能可以用来创建一个新的 AOF 文件来代替旧文件。并且两个文件所保存的数据库状态一样,但新文件不会包含任何冗余命令,所以新文件要比旧文件小得多。

而为什么新文件不会包含任何冗余命令呢?

那是因为这个重写功能是通过读取服务器当前的数据库状态来实现的。虽然叫做「重写」,但实际上并没有对旧文件进行任何读取修改。

比如旧文件保存了对某个 key 有 4 个 set 命令,经过重写之后,新文件只会记录最后一次对该 key 的 set 命令。因此说新文件不会包含任何冗余命令。

因为重写涉及到大量 IO 操作,所以 Redis 是用子进程来实现这个功能的,否则将会阻塞主进程。该子进程拥有父进程的数据副本,可以避免在使用锁的情况下,保证数据的安全性。

那么这里又会存在一个问题,子进程在重写过程中,服务器还在继续处理命令请求,新命令可能会对数据库进行修改,这会导致当前数据库状态和重写后的 AOF 文件,所保存的数据库状态不一致。

为了解决这个问题,Redis 设置了一个 AOF 重写缓冲区。在子进程执行 AOF 重写期间,主进程需要执行以下三个步骤:

  • 执行客户端的请求命令
  • 将执行后的写命令追加到 AOF 缓冲区
  • 将执行后的写命令追加到 AOF 重写缓冲区

当子进程结束重写后,会向主进程发送一个信号,主进程接收到之后会调用信号处理函数执行以下步骤:

  • 将 AOF 重写缓冲区内容写入新的 AOF 文件中。此时新文件所保存的数据状态就和当前数据库状态一致了
  • 对新文件进行改名,原子地覆盖现有 AOF 文件,完成新旧文件的替换。

当函数执行完成后,主进程就继续处理客户端命令。

因此,在整个 AOF 重写过程中,只有在执行信号处理函数时才会阻塞主进程,其他时候都不会阻塞。

迷失自我的程序员

到这里,RDB 和 AOF 我都介绍完了。但是在实际工作中,我们到底采用哪种方式呢?AOF 会不会有阻塞发生呢?关于这些问题,我们后面继续分享!

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号1:xmtxtt(5000人已满),微信号2:codedq(5000人已满),微信号3:xttblog(超2800)。备注:“xttblog”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!

本文原文出处:业余草: » 都9102了,你还不懂Redis的持久化?