面试官:今天要不来聊聊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的内存满了,但业务还在写数据,会怎么样?
候选者:嗯,这个问题我也遇到过
候选者:一般来说,我们会淘汰那些「不活跃」的数据,然后把新的数据写进去
候选者:更多情况下,还是做好对应的监控和容量的考量吧
候选者:等容量达到阈值的时候,及时发现和扩容