Redis 存储数据时,对于同一份数据,分别在内存和硬盘上都进行了存储,当查询某个数据时,直接从内存中读取,硬盘的数据用来在 Redis 重启时恢复内存中的数据,Redis 提供了两种内存持久化的策略
1. RDB 持久化策略
定期备份,会在指定的时间间隔内,将内存中的数据集快照写入磁盘,
1.1. 手动触发
"定期"可以手动触发,通过 Redis 客户端,执行save
命令或者bgsave
命令来触发快照生成,不过执行save
命令时,Redis 会集中处理快照,就会阻塞其它命令,而bgsave
就不会影响Redis 服务器处理其它请求和命令,此时采用的是一种"多进程"的方式来完成的
![](https://i-blog.csdnimg.cn/img_convert/a18737cf23b40c5fb708755e68c1a7d2.png)
- 首先,执行
bgsave
命令之后,Redis 父进程会判断当前进程是否存在其他正在执行的子进程,如 RDB/AOF 子进程,如果存在就直接返回,不存在的话就执行fork
创建子进程,fork 过程中父进程会阻塞 - 当父进程 fork 完成后,不再阻塞父进程,可以执行其他命令
- 子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换
- 进程发送信号给父进程表示完成,父进程更新统计信息
由于 fork 采用的是"写时拷贝"的策略,所以在进行 bgsave 的过程中,绝大部分数据时不需要改变的,整体来说拷贝过程也挺快
而 Redis 生成的 RDB 文件是存放在 Redis 的工作目录中的,也可以在配置文件中找到该路径
![](https://i-blog.csdnimg.cn/img_convert/b853db81321e170538c9968a3c05cc9c.png)
切换到该目录之后就能找到 rdb 文件了
![](https://i-blog.csdnimg.cn/img_convert/9e5a9bf1215112b25f3a2b5e7cc3879f.png)
执行 RDB 镜像操作时,会把生成的快照数据先保存在一个临时文件中,当这个快照生成完毕之后,再把原来的 rdb 文件删除,然后更新临时文件的名称为 dump.rdb,如果是save
命令就直接在当前进程中往同一个文件中写入数据了
需要注意的是 dump.rdb 文件不能随便修改,可能会使 Redis 无法正常启动
![](https://i-blog.csdnimg.cn/img_convert/60a970c3382535d1b9839d44ffb34294.png)
通过执行 redis-check-rdb dump.rdb
可以检查格式是否有误
通过手动输入命令bgsave
的方式来生成快照:
![](https://i-blog.csdnimg.cn/img_convert/f036a58f76a305f87bb94b4523851303.png)
1.2. 自动触发
除了手动,也可以自动触发,通过 shutdown 命令关闭 Redis 服务器时会触发自动生成快照,进行主从复制的时候,主节点也会自动生成 rdb 快照,然后把 rdb 快照内容传输给从节点,所以说,在正常关闭 Redis 服务器时会触发生成 rdb,如果是异常重启,例如 kill -9 或者服务器掉电这样的情况就不会触发,也就会丢失当前没有存储快照的数据
此外,在 Redis 的配置文件中也可以配置一些 Redis 自动触发快照的条件:
![](https://i-blog.csdnimg.cn/img_convert/9a3873d4af6b971002561517a2943bc5.png)
这里表示需要满足过 900 秒,并且修改 1 次才会自动触发,如果设置为 save ""
表示取消自动触发
如果修改配置文件之后,重启客户端配置才会生效
2. AOF 持久化策略
由于 RDB 采用的是定时备份的策略,所以两次快照之间的数据就可能会丢失,而 AOF 采用的是实时备份的策略。
修改配置文件中的 appendonly 为 yes 就能够开启 AOF
![](https://i-blog.csdnimg.cn/img_convert/7f0d023d3572c605da78cf8a86fed129.png)
之后每次进行的操作都会被记录到 appendonly.aof 文本文件中,当 redis 服务器异常关闭,再次启动时也能通过读取 appendonly.aof 文件进行恢复
![](https://i-blog.csdnimg.cn/img_convert/9f5374c109d3121eb9f49e28a1a170a6.png)
2.1. 写入流程
采用 AOF 之后,redis 既需要写硬盘,有需要写内存,但也并不会对性能有过大的影响,AOF 采用的是先把数据写入内存缓冲区,积累到一定数量时再统一写入硬盘,也就大大减少了写入硬盘的次数
![](https://i-blog.csdnimg.cn/img_convert/b4a1922dd67c3eb03cbd82888042f74c.png)
但是,当面的策略也存在一个问题,当数据在缓冲区中没来的及写入内存时,Redis 服务器出现问题了,那么次数缓冲区的数据就丢失了,所以控制缓冲区的刷新频率就很有必要了,Redis 中提供了三种不同的刷新缓冲区策略:
|--------------------------|-------------------------------|----------------------|
| 策略 | 含义 | 特点 |
| appendfsync always | 每次执行写命令后都立即将 AOF 缓冲区中的内容刷新到磁盘 | 数据安全性最高,Redis 性能最低 |
| appendfsync everysec | 每秒将 AOF 缓冲区中的内容刷新到磁盘一次 | 在性能和数据安全性之间做了一个较好的平衡 |
| appendfsync no | 由操作系统决定何时将 AOF 缓冲区中的内容刷新到磁盘 | 数据安全性最低 |
2.2. 重写机制
由于 aof 文件是记录每一次的操作的,所以会持续增长,增长到一定大小就会影响 Redis 下一次启动的时间,对于一些操作的记录其实也可以进行合并,所以存在很多不必要的记录
![](https://i-blog.csdnimg.cn/img_convert/959282378d5d9fd8287f9a3fc20d32b7.png)
重写的时候就是把当前内存中的数据获取出来,以 AOF 的格式写入到一个新的 AOF 文件中,也就是记录一次结果状态,也就类似于 RDB 生成的快照,只不过 RDB 那里是按照二进制来生成的,AOF 重写是按照文本格式来生成的
![](https://i-blog.csdnimg.cn/img_convert/a72464f5d80ce7788ff94aa89bc433b8.png)
在重写的时,还是会 fork 一个新的进程,父进程还继续接收客户端新的请求,继续把这些请求产生的 AOF 数据先写入到缓冲区,再刷新到原有的 AOF 文件里,只不过父进程又准备了一个 aof_rewrite_buf 缓冲区,专门用来存放 fork 之后接收到的数据,子进程把 AOF 数据写完之后,父进程再把 aof_rewrite_buf 缓冲区中的内容也写入到新的 AOF 文件中,然后替换到原来的 AOF 文件
如果在执行bgrewriteaof
时,发现 Redis 正在进行 AOF 重写,就会直接返回,如果 Redis 正在生成 rdb 文件的快照,AOF 重写操作就会阻塞,快照生成完毕再执行重写
3. 混合持久化
在配置文件中 aof-use-rdb-preamble yes
表示开启混合持久化
![](https://i-blog.csdnimg.cn/img_convert/752fb2c7455aabf1da51be3722c78997.png)
执行bgrewriteaof
之后再来看 appendonly.aof 文件,发现存储的结果变味了和 rdb 文件一样的二进制
![](https://i-blog.csdnimg.cn/img_convert/c776a0de11a738706aadf890f24ed39b.png)
![](https://i-blog.csdnimg.cn/img_convert/a9809e366d1ffb826a02b0f2071b64f2.png)
是因为此时采用了"混合持久化"的方式,也就是按照 aof 的方式,把每一个操作都记录到文件中,在触发 aof 重写时,就会把当前的内存状态按照 rdb 的二进制格式写入到新的 aof 文件中,之后再存储就还是原来的 aof 文本格式
![](https://i-blog.csdnimg.cn/img_convert/0cc3da0d08b9c26b561d50d28d8fef11.png)