Redis持久化机制有哪些?它的优缺点和使用场景?
只针对写操作才会持久化
Redis持久化是为了解决内存数据容易丢失的问题。既然是数据恢复,那么恢复的就是数据变化后的状态。而数据只有在写操作之后才有变化。读操作只是查询数据并不会改变数据的状态,所以操作不会被持久化。
RDB(Redis Database)持久化
快照(Snapshotting)持久化,在指定的时间间隔内将内存中的数据写入到磁盘。
RDB持久化的触发方式
手动触发
- SAVE命令:同步保存操作,会阻塞主线程,知道RDB文件生成完毕。生产环境下不推荐使用。
 - BGSAVE命令:后台异步执行。Redis主线程会fork一个子进程进行RDB文件生成,主线程继续处理客户端响应。只会在fork子进程的时候会有短时的暂停阻塞响应,这是推荐的手动触发的方式。
 
自动触发
redis_conf配置:通过配置save
规则,当在 秒内,触发至少 次写操作时,Redis会自动执行一次BGSAVE操作。 1
2
3save 900 1: 900秒内至少有一次key被修改。
save 300 10: 300秒内至少有个10次key被修改。
save 60 10000: 60秒内至少有10000次key被修改。FLUSHALL / FLUSHDB命令:执行清除数据库时,如果配置了RDB也会生成一次RDB保存(保存一个空的RDB文件)。
SHUTDOWN命令:正常关闭Redis时,如果没有配置AOF,默认会执行一次SAVE命令,生成RDB文件。
主从复制时:当进行全量同步时,主节点会生成RDB文件发送给从节点。
工作原理
- Redis主线程接收到RDB的请求(手动或者自动触发)
 - 主进程fork一个子进程
 - 子进程遍历Redis内存中的数据将数据写到一个临时的rdb文件中。这个过程中采用了写时复制(copy on write , cow)技术,主进程和子进程同时共享同一个内存页数据,当主进程进行内存修改时,操作系统会复制一个新的内存页使用。fork子进程继续使用旧的内存页数据。
 - 当子进程写完rdb数据后,用这个临时的rdb文件替换掉原来的dump.rdb文件。
 - 子进程退出,通知主进程RDB持久化完成。
 
优点和缺点
优点
二进制文件,仅记录数据结果,恢复速度快,文件紧凑,适合备份
缺点
数据丢失风险:RDB是定时保存的,如果最后一次快照后的数据没有进行保存就宕机,就丢失了最后一次快照后的数据。
适用场景
对数据完整度要求不严格,允许丢失少量数据,用于灾难恢复。
AOF(Append Only File)持久化方式
只追加文件,记录Redis服务器收到的所有的写操作,以文本方式追加到AOF文件中。
工作原理
- 命令追加(Append):当Redis执行写操作时,会将执行命令追加到AOF缓冲区(内存)中。
 - 文件写入(Write):根据AOF配置的规则会将AOF缓冲区中的数据写入到操作系统内核缓冲区。此时还没有写入到磁盘。
 - 文件同步(Fsync/Sync):根据配置的同步策略,会将操作系统内核缓冲区中的数据写入到磁盘。
 - 重启加载:默认优先加载AOF文件进行恢复,生成一个伪客户端执行这些命令,就像客户端发送指令到Redis服务器一样,自己给自己发。
 
appendfsync同步策略:
- always:每次的写指令都会同步,最安全,但是性能开销大。
 - everysec:每秒调用一次,默认方案,性能较好,可能会丢失1s数据。
 - no:不主动同步,根据操作系统自己同步,性能最优。
 
AOF重写(Rewrite)
随着 AOF 文件越来越大,Redis 会在满足条件时(例如文件大小达到一定阈值且增量百分比达到预设值)自动触发 BGREWRITEAOF。
- Redis 
fork一个子进程。 - 子进程读取当前内存中的数据。
 - 子进程将这些数据转化为最少的写命令集合,写入一个新的临时 AOF 文件。例如,如果你对 
counter这个 key 做了 1000 次INCR操作,最终结果是 1000,那么新的 AOF 文件中可能只会有一个SET counter 1000命令。 - 主进程在重写期间继续将新命令追加到旧的 AOF 文件和一个新的 AOF 缓冲区中。
 - 当子进程完成重写后,主进程会将重写期间生成的新命令追加到新的 AOF 文件尾部。
 - 最后,主进程原子性地用新的 AOF 文件替换旧的 AOF 文件。
 
优缺点
优点
数据完整性高,基本不丢失数据,可读性高。
缺点
- 文件可能会越来越大,占用存储空间。
 - 恢复速度较慢
 
适用场景
对数据完整性要求高,不希望丢失数据。
RDB和AOF混合使用持久化方式
这是Redis 4.0及更高版本推荐的持久化方式。它结合了两者的优点,在数据恢复时,速度更快且数据丢失更少。
最佳实践
- 开启RDB和AOF,并开启混合持久化。
 - 将AOF设置为
everysec策略,确保数据丢失最小。 - RDB可以作为AOF的补充备份,或者用于大规模数据恢复时快速加载初始数据。
 
1  | ################################## RDB CONFIGURATION ##################################  | 
在生产环境中,通常会同时开启RDB和AOF,以提供最大的数据安全保障。RDB可以用于灾难恢复时的快速全量恢复,而AOF则保证了数据丢失的最小化。
核心流程
无论 AOF 重写是自动触发(根据 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size)还是手动触发 (BGREWRITEAOF 命令),其流程大致如下:
fork子进程:- Redis 主进程调用 
fork()创建一个 AOF 重写子进程。 - 同样地,写时复制(COW) 机制在这里发挥作用,主进程和子进程一开始共享内存页。
 
- Redis 主进程调用 
 - 子进程生成 RDB 部分:
- AOF 重写子进程不会像传统的 AOF 重写那样直接将命令写入。
 - 相反,它会像 RDB 持久化一样,遍历当前 Redis 内存中的所有数据(也就是 
fork瞬间的数据状态)。 - 然后,将这些数据以RDB 的二进制格式写入到一个临时文件中。这部分是整个混合文件的前缀,被称为 RDB Preamble(RDB 前言)。
 
 - 主进程记录增量 AOF:
- 在 AOF 重写子进程忙于生成 RDB Preamble 的同时,Redis 主进程继续处理客户端的请求。
 - 所有在重写期间发生的新写操作命令,都会被主进程同时记录到两个地方:
- 当前的 AOF 缓冲区:这些命令会像往常一样,根据 
appendfsync策略写入到旧的appendonly.aof文件中,以确保数据不丢失。 - AOF 重写缓冲区:这些命令也会被复制一份,累积到一个专门用于 AOF 重写过程的内存缓冲区中(通常称为 AOF rewrite buffer)。
 
 - 当前的 AOF 缓冲区:这些命令会像往常一样,根据 
 
 - 子进程追加 AOF 尾部:
- 当 AOF 重写子进程完成 RDB Preamble 的写入后,它会通知主进程。
 - 接着,主进程会将步骤3中累积在 AOF 重写缓冲区里的增量写命令通过管道发送给子进程。
 - 子进程接收到这些增量命令后,会将其以AOF 的文本格式追加到之前写入的 RDB Preamble 文件的末尾。这部分就是混合文件的 AOF Tail(AOF 尾部)。
 
 - 原子性替换:
- 当子进程完全写入新的混合格式 AOF 文件(包含 RDB Preamble 和 AOF Tail)后,它会通知主进程。
 - 主进程会用这个新的临时文件原子性地替换掉旧的 
appendonly.aof文件。 
 - 子进程退出:AOF 重写完成,子进程退出。
 
因此,混合持久化是 Redis 推荐的生产环境持久化方案,它在性能、数据安全和恢复效率之间取得了最佳平衡。