Redis持久化机制详解
持久化
持久化是什么
redis 跑在内存中,当程序重启或者服务崩溃,数据就会丢失,如果业务场景希望重启之后数据还在,就需要持久化,即把数据保存到可永久保存的存储设备中
持久化的方式
RDB
简介
RDB(Redis DataBase):记录 redis 某个时刻的全部数据,本质就是数据快照,直接保存二进制数据到磁盘,后续通过加载 RDB 文件恢复数据

如何开启
在 redis 的配置文件 redis.conf 中
- 有如下配置

- 配置语法是 save interval num:表示每间隔interval 秒,至少有 num 条写数据操作(增删更新),会激活 RDB 持久化
- 自动快照时, save 实际触发 bgsave 命令,因为 save 会阻塞,bgsave 是 fork 一个子进程做快照
上图的意思
- 每 900s,至少有 1 条写数据操作
- 每 300s,至少有 10 条写数据操作
- 每 60s,至少有 10000 条写数据操作
他们是并集关系,只要满足其中一个条件,就会触发 RDB 持久化。
默认配置

RDB 文件存在哪里
以下参数决定文件会存在哪里

二进制文件的形式
【精选】Redis(9)----RDB文件结构_rdb文件内容_cb414的博客-CSDN博客
没有可读性的二进制文件,但是开头有 REDIS 关键字,后面混合持久化会用到
RDB 触发时间
RDB 是几分钟才做一次持久化
- 虽然可以 fork 出子进程来做全量快照,但是一秒一次,性能开销很大。
- 有可能上秒的快照还没完成,下一秒又来了,所以 fork 是会导致主线程阻塞的
- RDB 快照触发间隔比较难确定,原则不能太短
RDB 具体做了什么
先看看 redis RDB 持久化后的输出

流程图
- fork 一个子进程来专门做 RDB 持久化
- 子进程写数据到临时的 RDB 文件
- 写完后,用新的 RDB 文件替换旧的 RDB 文件

this method allows redis to benefit from copy-on-write s semantics
执行 RDB 持久化过程,redis 依然可以继续处理操作命令,就是是能被修改的,用了写时复制技术
VLDB 顶会论文 Async-fork 解读与 Redis 实践 | 得物技术
AOF
简介
AOF(Append Only File):记录执行的每条命令,重启之后通过重放命令来恢复数据,AOF 本质是记录操作日志,后续通过日志重放恢复数据

怎么开启
redis.conf

AOF 写入流程

每次执行请求,都会写入到 AOF,会不会影响执行性能
- 肯定是会的
redis 的 3 种 刷盘策略(写入策略)

- appendfsync always,每次请求都刷入AOF,用官方的话说,非常慢,非常安全
- appendfsync everysec,每秒刷一次盘,用官方的话来说就是足够快了,但是在崩溃场景下你可能会丢失1秒的数据。
- appendfsync no,不主动刷盘,让操作系统自己刷,一般情况Linux会每30秒刷一次盘,这种策略下,可以说对性能的影响最小,但是如果发生崩溃,可能会丢失相对比较多的数据。
redis 的建议是每秒刷一次
AOF 写入细节
写入 AOF 是分好几步

第一步:将数据写入AOF缓存中,这个缓存名字是aof_buf,其实就是一个sds数据

第二步:aof_buf 对应数据刷入内核缓冲区
什么时候做这个事情?事实上,Redis源码中一共有4个时机,会调用一个叫flushAppendOnlyFile的函数,这个函数会使用write函数来将数据写入操作系统缓冲区:
处理完事件处理后,等待下一次事件到来之前,也就是beforeSleep中。- 周期函数serverCron中,这也是我们打过很多次交道的老朋友了
- 服务器退出之前的准备工作时
- 通过配置指令关闭AOF功能时
第三步:刷盘
即调用系统的flush函数,刷盘其实还是在flushAppendOnlyFile函数中,是在write之后
但是不一定调用了flushAppendOnlyFile,flush就一定会被调用,这里其实是支持一个刷盘时机的配置,这一步受刷盘策略影响是最深的:
如果是appendfsync always策略,那么就立刻调用redis_fsync刷盘
如果是AOF_FSYNC_EVERYSEC策略,满足条件后会用aof_background_fsync使用后台线程异步刷盘。
AOF 例子
执行如下命令

会生成如下 AOF 文件

AOF 重写
AOF 是不断写入的,为了避免 AOF 不断膨胀,redis 采用重写的方式来解决
Redis可以在AOF文件体积变得过大时,自动地在后台Fork一个子进程,专门对AOF进行重写。
说白了,就是针对相同Key的操作,进行合并,比如同一个Key的set操作,那就是后面覆盖前面。
在重写过程中,Redis不但将新的操作记录在原
,而且还会记录在AOF重写缓冲区。
一旦新AOF文件创建完毕,Redis 就会将重写缓冲区内容,追加到新的AOF文件,再用新AOF文件替换原来的AOF文件。

AOF达到多大会重写,实际上,这也是配置决定,默认如下,同时满足这两个条件则重写。

也就是说,超过64M的情况下,相比上次重写时的数据大一倍,则触发重写,很明显,最后实际上还是在周期函数来检查和触发的
进行持久化的时机
1. 主动执行 save
会阻塞主线程
2. 主动执 bgsave
backgroundsave 不会阻塞主进程
fork 一个子进程来执行快照
3. 达到持久化配置的阈值
4. 执行 bgsave
5. 正常关闭程序
执行一次阻塞持久化 save
正常关闭是不会丢失数据的,崩溃才会(如果考虑主从同步,主节点没崩溃,从节点崩溃就算主节点正常关闭也会丢失数据)
RDB 还是 AOF
- 如果业务本身只是缓存数据且并不是海量访问,不用开持久化
- 如果业务本身对数据非常重视,需要保证数据的强一致性,可以同时开启 AOF 和 RDB
- 同时开启的情况下,只会用 AOF 来加载,但如果只有 RDB 文件而没有 AOF 文件(损坏了),是不会用 RDB 恢复数据的
- 对上一点的解释:如果你自主选择开启 AOF,要表明数据强一致性,但是 AOF 缺失了,此时是不会用 RDB 去恢复数据,因为 RDB 可能会少了很多数据,会选择此时启动一个空库
- 虽然 RDB 看起来没什么作用,但是 RDB 作为时间数据快照,是一个很好的兜底文件,存在磁盘中。
- 除非你可以接受丢失几分钟级别的数据,可以只开启 RDB。
- 单独开启 AOF,redis 不建议,因为如果决定走数据备份的方案,镜像保存始终是数据库行之有效的解决方案,所以 RDB 是默认开启的,而 AOF 不是
