1. 引子
redis所有数据保存在内存中,为防止数据丢失,redis通过对数据的更新异步地保存到磁盘中来实现持久化。为实现持久化,redis有两种方式可供选择:RDB和AOF。
RDB:快照形式,保存某一时刻的所有内存数据到磁盘中的二进制文件中。
AOF:将执行过的命令保存到日志中,恢复数据就是重新执行一遍日志中命令的过程。
2. RDB
RDB存储触发机制分为手动触发和自动触发两类。
2.1 手动触发
2.1.1 save命令
- 客户端执行save命令后将会创建一个RDB文件。在执行save时会进行同步阻塞,如果耗时较长时,其他客户端再执行其他命令就会发生等待。
- 如果本次save操作时已有存在的旧的RDB文件,那么本次save操作将会生成一个新的临时的RDB文件,等到save执行完后,将这个新的RDB文件替换旧的RDB文件。
- 线上由于数据量大,使用save命令由于阻塞比较危险,已经废弃该操作。
2.1.2 bgsave命令
- 客户端执行bgsave命令时,当前redis进程将会fork出一个子进程,并在子进程中进行创建和保存RBD文件的过程。当子进程保存完后,返回"bgsave successfully"结果给主进程。使用bgsave除了在fork子进程的时候会阻塞(很短暂的时间),其他步骤不会进行阻塞。
2.2 自动触发
- redis内部设置了自动执行bgsave命令的配置文件,如可以设置60秒内发生了10000次写操作就可以触发一次RBD文件的生成。
- 如果具备主从复制结构,从节点执行全量复制操作时,主节点会自动执行bgsave命令生成RDB文件并发送给从节点。
- 执行debug reload命令重新加载redis时也会自动执行bgsave。
- 默认情况下执行shutdown命令时,如果没有开启AOF持久化功能也会自动执行bgsave。
配置文件conf:
- dir:RDB文件的存储目录
- dbfilename:RDB文件的文件名
- Save 60 10000 // 60秒内执行了10000次写操作就触发RDB的自动生成
3. AOF
由于RBD具有耗时耗性能,不可控和丢失数据等问题,引出了另一种持久化方式AOF。AOF以日志的形式来保存了每次的写操作,重启时只要再执行一遍AOF文件中的所有写命令就可以达到恢复数据的目的。AOF是redis主流的持久化技术。
AOF有三种写入策略:always,everysec,no。
3.1 AOF工作流程
从图中可以看到AOF写入时并不是直接将命令写入到磁盘文件中,而是先写入到缓冲区中(因为磁盘写入速度慢,内存写入速度快),然后通过不同的写入策略将内存的数据同步到文件中。
3.2 AOF写入策略
Always: 每执行一次写入命令就会同步将缓冲区中的数据同步到文件中。这种策略的问题就是IO开销较大,不建议使用。
Everysec:每秒一次同步缓冲区中的数据到文件中。问题是可能会丢失1秒的数据。是建议的同步策略
No:由操作系统来确定何时同步,使用者不用管。由于存在安全性的问题,不建议使用。
3.3 重写机制
随着命令不断写入会导致文件越来越大,为了解决这个问题,redis实现了AOF重写机制压缩文件体积。
重写机制会对如下几种情况进行优化:
- 过期的数据(如设置了过期时间,超期后没有用的)
- 列表等分多次插入的命令合并为一条名称一次性插入
- 后面的命令的值对前面的命令的值覆盖的情况,如果set hello world;set hello java;实际只需要保存最后一次命令就行。
通过重写机制,可以减少磁盘占用量,加速恢复速度。
同样的,AOF重写可以分为手动触发和自动触发两种方式。
- 手动触发:执行bgrewriteaof命令,创建一个子进程来执行重写过程。
- 自动触发:AOF重写配置,conf文件中,auto-of-rewrite-min-size表示AOF文件重写需要的尺寸;auto-of-rewrite-percentage表示AOF文件增长率。
使用AOF时,conf相关配置如下:
appendonly yes // 启动AOF持久化
appendfilename "xxx.aof" // 指定文件名
appenfsync everysec // 重写策略,每秒执行一次
dir // 保存日志的目录
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
加上重写机制后,AOF写入流程如下:
要注意的是为保证子进程针对原缓冲区进行重写过程中客户端新写入的命令不丢失,redis单独创建了另外一块缓冲区,等到重写结束后再将这个单独的缓冲区的数据写入到AOF文件中。