02. Redis持久化

3y 2021-08-19 15:53:57
Categories: Tags:

面试官今天要不来聊聊Redis的持久化机制吧?

候选者:嗯,没问题的

候选者:在上一次面试已经说过了Redis是基于内存的

候选者:假设我们不做任何操作,只要Redis服务器重启(或者中途故障挂掉了),那内存的数据就会没掉

候选者:我们作为使用方,肯定是不想Redis里头的数据会丢掉

候选者:所以Redis提供了持久化机制给我们用,分别是RDB和AOF

候选者:RDB指的就是:根据我们自己配置的时间或者手动去执行BGSAVE或SAVE命令,Redis就会去生成RDB文件

候选者:这个RDB文件实际上就是一个经过压缩的二进制文件,Redis可以通过这个文件在启动的时候来还原我们的数据

候选者:而AOF则是把Redis服务器接收到的所有写命令都记录到日志中

候选者:Redis重跑一遍这个记录下的日志文件,就相当于还原了数据

面试官那我就想问了,你上次不是说Redis是单线程吗

面试官那比如你说的RDB,它会执行SAVE或BESAVE命令,生成文件

面试官那不是非常耗时的吗,那如果只有一个线程处理,那其他的请求不就得等了?

候选者:嗯,没错,Redis是单线程的。

候选者:以RDB持久化的过程为例,假设我们在配置上是定时去执行RDB存储

候选者:Redis有自己的一套事件处理机制,主要处理文件事件(命令请求和应答等等)和时间事件(RDB定时持久化、清理过期的Key等的)

候选者:所以,定时的RDB实际上就是一个时间事件

候选者:线程不停地轮询就绪的事件,发现RDB的事件可执行时,则调用BGSAVE命令

候选者:而BGSAVE命令实际上会fork出一个子进程来进行完成持久化(生成RDB文件)

候选者:在fork的过程中,父进程(主线程)肯定是阻塞的。

候选者:但fork完之后,是fork出来的子进程去完成持久化。处理请求的进程该干嘛的就干嘛

候选者:所以说啊,Redis是单线程,理解是没错的,但没说人家不能fork进程来处理事情呀,对不对

候选者:还有就是,其实Redis在较新的版本中,有些地方都使用了多线程来进行处理

候选者:比如说,一些删除的操作(UNLINK、FLUSHALL ASYNC等等)还有Redis 6.x 之后对网络数据的解析都用了多线程处理了。

候选者:只不过,核心的处理命令请求和响应还是单线程。

面试官那AOF呢?AOF不是也要写文件吗?难道也是fork 了个子进程去做的?

候选者:emm,不是的。AOF是在命令执行完之后,把命令写在buffer缓冲区的(直接追加写)

候选者:那想要持久化,肯定得存盘嘛。Redis提供了几种策略供我们选择什么时候把缓冲区的数据写到磁盘

候选者:我记得有:每秒一次/每条命令都执行/从不存盘;一般我们会选每秒一次

候选者:Redis会启一个线程去刷盘,也不是用主线程去干的

面试官那如果把执行过的命令都存起来

面试官等启动的时候是可以再把这些写命令再执行一遍,达到恢复数据的效果

面试官这样会有什么样的问题吗?

候选者:嗯,问题就是,如果这些写入磁盘的「命令集合」不做任何处理,那该「命令集合」就会一直膨胀

候选者:其实就是该文件会变得非常大

候选者:Redis当然也考虑了这一点,它会fork个子进程会对「原始」命令集合进行重写

候选者:说白了就是会压缩,压缩完了之后只要替换原始文件就好了

面试官那我又想问了,既然它是fork一个进程来对AOF进行重写的

面试官前面你也提到了再fork时,主进程是阻塞的,但fork后,主进程会继续接收命令

面试官你是说重写完(压缩)会进行文件覆盖

面试官那这样不会丢数据吗?毕竟主进程在fork之后是一直会接收命令的

候选者:哦,我明白你的意思了。

候选者:其实做法很简单啊,在fork子进程之后,把新接收到命令再写到另一个缓冲区不就好了吗

面试官:可以

面试官:那AOF和RDB用哪一个呢?

候选者:主要是看业务场景吧,我们这边是基于Redis自研了一套key-value存储

面试官自研的?你们的Redis架构是什么?

候选者:别别别,当我没说。就是开源的,开源的。我们回到RDB和AOF上吧。

候选者:在新增namespace(实例) 的时候也会让你选择对应的使用场景

候选者:就是会让你通过不同的应用场景进行配置选择

候选者:比如说,业务上是允许重启时部分数据丢失的,那RDB就够用了(:

候选者:RDB在启动的时候恢复数据会比AOF快很多

候选者:在Redis4.0以后也支持了AOF和RDB混合

候选者:在官网是不建议仅仅只使用AOF的,如果对数据丢失容忍度是有要求的,建议是开启AOF+RDB一起用

候选者:总的来说,不同的场景使用不同的持久化策略吧

面试官:了解

面试官顺便我想问下,假如Redis的内存满了,但业务还在写数据,会怎么样?

候选者:嗯,这个问题我也遇到过

候选者:一般来说,我们会淘汰那些「不活跃」的数据,然后把新的数据写进去

候选者:更多情况下,还是做好对应的监控和容量的考量吧

候选者:等容量达到阈值的时候,及时发现和扩容

面试官:你这懂得有点多啊

本文总结

第一时间获取BATJTMD一线互联网大厂最新的面试资料以及内推机会关注公众号「对线面试官