当前位置:首页 > 问答 > 正文

深入聊聊Redis混合持久化那些事儿,感觉挺复杂但又特别关键

为什么需要“双保险”?——RDB和AOF各自的烦恼

要理解混合持久化,得先知道在它出现之前,Redis提供的两种“单保险”各有什么让人头疼的地方。

第一种保险叫RDB(快照),你可以把它理解为给整个数据库拍一张全景照片,这张照片非常紧凑,文件很小,当Redis需要重启时,就像看一张照片一样,能瞬间把整个数据库恢复到拍照那一刻的状态,速度非常快,它的致命缺点是“不连续”,如果系统在拍下一张照片之前突然崩溃了,那么从上一次拍照到崩溃之间的所有数据更新(比如新写的键值对、修改的数据)就全丢了,这就好比你每隔一小时给工作文档存一次盘,如果电脑在存盘后第59分钟死机,你这59分钟的工作就白干了。

第二种保险叫AOF(日志),它不拍照,而是像个非常尽责的秘书,把你对数据库做的每一个写命令(set name Jack”、“splice list1 apple”)都原原本本地记在一个日志文件里,当Redis重启时,它不需要恢复数据,而是把这个日志文件里的命令从头到尾再执行一遍,这样就能精确地重建出崩溃前的数据状态,理论上,如果你设置成每条命令都立刻刷盘,最多只会丢失一秒的数据,数据安全性高了很多,但它的麻烦在于:第一,日志文件会变得非常大,因为记录了所有历史操作;第二,重启时重放这个巨大的日志文件,过程会非常非常慢,可能要花几个小时,这对于线上服务是不可接受的。

混合持久化:聪明的“合体”方案

你看,RDB和AOF一个重启快但易丢数据,一个数据安全但重启慢,那能不能把它们俩的优点结合起来呢?这就是Redis混合持久化诞生的初衷。

根据Redis官方文档的描述,混合持久化简单来说就是:在生成AOF日志文件时,不再是单调地追加命令,而是先拍一个RDB快照放在AOF文件的开头,然后再接着记录这个快照之后产生的新命令。

咱们来拆解一下这个过程:

  1. 当满足一定条件(比如距离上次重写过去了一定时间)时,Redis会触发AOF重写流程。
  2. 这时,子进程会先像往常一样,将当前内存中的数据库数据生成一个RDB格式的快照。
  3. 它不把这个RDB存成单独的文件,而是直接写入到一个新的AOF文件的开头部分
  4. 紧接着,在主进程生成这个RDB快照的过程中,新的写命令会像往常一样被缓冲在内存里,等RDB数据写完后,子进程再把这段时间累积的增量写命令(以AOF格式)追加到同一个新AOF文件的后面部分
  5. 用这个包含了“RDB头 + AOF尾”的新文件替换掉旧的AOF文件。

这样一来,最终得到的AOF文件就变成了一种“杂交”的形态:前半部分是二进制的RDB数据,后半部分是纯文本的AOF命令。

这个“合体”带来了什么好处?

这种混合模式简直是取长补短的典范:

  1. 重启速度大大加快:Redis重启加载数据时,首先看到的是文件开头的RDB快照,它可以用极快的速度先把大部分数据恢复出来,再重放文件后面那一小部分增量的AOF命令,用来弥补快照生成期间可能丢失的那一点点数据,这比从头到尾执行一个巨大的纯AOF文件要快太多了。

  2. 数据丢失风险极低:由于背后基于AOF机制,你仍然可以配置每秒同步或者每条命令同步,数据丢失的风险窗口和纯AOF模式是一样的,远小于单纯的RDB模式。

  3. 文件大小得到控制:虽然AOF文件还是会增长,但通过定期的重写(每次都从一个新的RDB快照开始),可以有效避免它无限膨胀下去,比纯AOF模式的文件要小一些。

一点小小的代价和注意事项

世上没有完美的事,混合持久化也有个小缺点,就是它的AOF文件的可读性变差了,以前的纯AOF文件,你可以用文本编辑器打开,像看操作历史一样检查命令,但现在文件开头是一大段二进制的RDB数据,对人类来说是乱码,只有Redis自己能看懂,这对于运维调试来说只是个小麻烦,相比于它带来的巨大好处,完全可以接受。

总结一下,你可以把混合持久化理解为一份“基础档案+动态更新”的完美方案,RDB快照是那份完整的、压缩过的基础档案,而AOF日志是后续的、持续不断的动态更新记录,需要恢复时,先快速建立基础档案,再应用最新的更新补丁,效率和安全兼得,正因为这种出色的平衡性,它成为了目前生产环境中最为推荐的持久化策略,如果你觉得它关键,那你的感觉是完全正确的,它确实是Redis数据高可用架构中至关重要的一块基石。

深入聊聊Redis混合持久化那些事儿,感觉挺复杂但又特别关键