Redis 持久化
本文将介绍 Redis 中的持久化。
一、Redis 持久化
Redis 会将数据全部存储于内存之中,因此拥有了极高的性能,但这也带来了断电后丢失数据的缺点。
针对这一问题,Redis 提供了数据持久化机制,它能够将内存中的数据保存到本地磁盘中,实现数据的持久存储。
Redis 提供了两种持久化机制:
- RDB
- AOF
二、RDB - 快照
1. 说明
RDB,即快照模式,是 Redis 默认的数据持久化方式,它将内存中所有的数据持久化并保存在内存快照文件中。
2. 阻塞与非阻塞
(1) 阻塞式
RDB 支持堵塞方式生成快照,在主线程中执行,将影响 Redis 的正常运行。
(2) 非阻塞式
RDB 模式会将内存中所有的数据一起保存,内存中的数据越多,需要耗费的性能越多,需要耗费的时间越长。
对于持久化,我们希望能做到两点:
- 不影响 Redis 的正常运行
- 持久化的数据要和内存中的数据一致,且越及时越好
为此,Redis 提供的的解决方案是:调用 fork() 方法创建子进程,子进程将 “立刻” 获得父进程当前的内存空间,通过子进程进行数据的持久化。
共享内存空间的实现机制是 COW,可以在不影响主进程的情况下获取内存中的所有数据,避免拷贝数据时性能的大量耗费。
具体请看:
3. 触发方式
(1) 手动触发 - 阻塞式
1 | |
执行 SAVE 命令后,Redis 服务器进程将被阻塞,直到持久化完毕,在此期间 Redis 将不能处理任何请求。
(2) 手动触发 - 非阻塞式
1 | |
BGSAVE 命令是非阻塞式的,在持久化执行过程中并不会影响 Redis 处理其它请求。
LASTSAVE 用于查看 BGSAVE 是否执行成功。
(3) 自动触发
主动触发策略可以在 Redis 的配置文件中查看和修改,如下:

save m n 的含义是:如果 m 秒内至少发生了 n 次变化,则执行持久化。
这里的持久化是非阻塞式持久化
4. 性能开销
快照的性能开销主要在以下三个方面:
- fork:fork 操作的 “页表拷贝” 会堵塞主线程,且主线程的内存越大堵塞时间越长
- 写时拷贝:如果在快照过程中,Redis 进行了写入操作,则需要进行写时拷贝,造成一定的性能开销
- 写入硬盘:将数据写入硬盘也会带来性能开销
三、AOF 持久化
1. 说明
AOF,又叫追加模式、日志模式,它会将 Redis 中已执行过的命令追加存储到 AOF 日志中。
2. 写入机制

Redis 会在接到客户端指令后,首先执行命令,再将命令追加存储至 AOF 日志中。
为什么不先写日志再执行?
如果先写日志,需要考虑写入前的语法检查、写入失败时的日志项删除,以保证日志和实际数据的一致性;
如果后写日志,命令执行成功便代表语句没有问题,可以直接记录
如果先写日志再执行,会造成操作的等待
3. 读取机制
Redis 会读取 AOF 日志中的命令,进行 “命令重演”,从而达到恢复数据的目的。
4. 写回策略
(1) 说明
Redis 为了提升效率,不会将 AOF 日志直接写入磁盘中,而是会首先将其放到缓存区中(write),在 “适当时机” 写回磁盘(fsync)。
(2) 写回策略配置
Redis 配置文件中存在配置项如下:
1 | |
该项的作用是指定 Redis 何时将数据从缓存区写回磁盘,其中:
always:
- 缓存区中每加入一条命令就写回一次
- 最慢
- 使用主线程进行
- 可以做到基本不丢数据,但是在每个写命令后都有一个慢速的落盘操作,将会影响主线程性能
everysec:
- 每一秒钟写回一次
- 默认
- 会使用后台的子线程异步完成
- 对主线程的性能影响小了很多,但是发生宕机时仍会丢失一秒钟的命令,在性能和数据完整性中取了个折中
no:
- 不主动写回,而是由操作系统决定何时写回
- 不安全,落盘时机不由 Redis 控制
5. 文件重写
(1) 为什么需要文件重写?
随着 Redis 的不断运行,命令逐渐增多,AOF 日志也势必会越来越大。
AOF 日志文件过大会带来以下几方面的问题:
- 文件系统本身可能对文件大小有最大限制
- 向 AOF 日志中继续追加命令时效率会降低
- 恢复时 “命令重演” 的耗时将会很长
因此,Redis 提供了文件重写功能,用于获取一个更小的 AOF 日志。
(2) 文件重写不是重写!
文件重写是一个有歧义的名字,它并不会对原本的 AOF 文件做任何读入、分析、写入操作,而是会直接读取内存中的内容生成一个完全新的 AOF 日志。
(3) 文件重写怎么做?
主进程
fork()出 bgrewriteaof 子进程,子进程获得主线程的内存拷贝,其中包含数据库中的最新数据主进程继续处理请求并维护原有的 AOF 日志
子进程对内存中的数据进行遍历,将数据转化为一系列的操作语句,写入一个新的 AOF 日志中
当子进程写入完成后,向主进程发送信号,要求将 “重写” 期间发生的操作追加到新的 AOF 日志中
用新的 AOF 日志替代原有的 AOF 日志
(4) 手动重写
1 | |
(5) 自动重写
配置文件中关于自动重写的配置项如下:
1 | |
其中,
auto-aof-rewrite-percentage:表示超过最小文件体积后,每增大多少进行自动重写auto-aof-rewrite-min-size:表示触发自动重写的最小文件体积
因此,应用上面的配置项时,触发自动重写的时机为:64mb 128mb 256mb ···。
四、RDB 和 AOF 的对比
RDB 全量保存;
AOF 增量保存
RDB 持久化需要一次备份所有数据,耗费资源且耗费时间;
AOF 持久化每次只追加少量命令,较为轻量
RDB 耗费较大,因此备份不能过于频繁,以免影响服务器的性能;
AOF 会记录每条命令,并(默认)每秒持久化一次,备份间隔较短
RDB 因为备份时间较长、备份间隔较长的原因,宕机会将会丢失一部分最新数据;
AOF 在默认磁盘写入策略下,最多只会丢失一秒的数据
RDB 恢复速度较快;
AOF 恢复速度较慢
RDB 有阻塞和非阻塞两种方式;
AOF 始终非阻塞
五、RDB 和 AOF 混合使用
在 Redis 4.0 中提出了混合使用 RDB 和 AOF 的方法,简单来说,以一定的频率创建 RDB 内存快照,在两次快照之间,使用 AOF 日志记录所有的命令。
这样的做法有以下几点好处:
- 可以避免为了不丢失数据而频繁创建 RDB 快照带来的性能开销
- 可以避免 AOF 日志记录过多内容(现在只需要记录间隔期的少量命令)而出现的文件过大问题
- 可以尽可能地避免数据的丢失
参考
- Redis
- Redis 教程 | 菜鸟教程
- Redis数据库学习教程(快速入门版)
- Redis 核心技术与实战