Redis持久化整理
RDB快照
在指定的时间间隔内将内存中的数据集快照写入磁盘,默认的文件名为dump.rdb;
在默认情况下,Redis将内存数据库快照保存在名字为dump.rdb的二进制文件中;
在redis.conf配置下可以看出,如下:
- 测试redis-cli SHUTDOWN关闭redis进程后,数据是否恢复
在redis中保存几条数据
立刻停掉redis进程
重启redis服务,之前保存的数据还在,通过redis-cli SHUTDOWN这种方式去停掉redis,其实是一种安全退出的模式,redis在退出的时候会将内存中的数据立即生成一份完整的rdb快照,dump.rdb;
- 测试kill -9 关闭redis进程后,数据是否恢复
使用kill -9 将redis进程杀掉,docker搭建的使用docker kill命令,发现redis数据没有进dump文件,之前的数据丢失;
重启redis服务,之前保存的数据不在了;
产生快照的方式:
- save m n
- save m n 表示m秒内数据集存在n次修改 时,自动触发bgsave命令;
- 可以对 Redis 配置文件进行设置, 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动保存一次数据集,改动包括新增或者修改,不包括查询,自动保存一次数据集:
save 900 1 则表明在 900 秒内,至少有一个键发生改变,就会触发 RDB 持久化 save 300 10 则表明在 300 秒内,至少有10个键发生改变,就会触发 RDB 持久化 save 60 10000 则表明在 60 秒内,至少有10000个键发生改变,就会触发 RDB 持久化
满足以上任意一个条件,Redis 就会自动触发bgsvae命令进行持久化工作;关闭RDB只需要将所有的save保存策略注释掉即可;
- 可以手动执行命令生成RDB快照,进入redis客户端执行命令save或bgsave可以生成dump.rdb文件,每次命令执行都会将所有redis内存快照到一个新的rdb文件里,并覆盖原有rdb快照文件;
save和bgsave对比:
命令 | save | bgsave |
IO类型 | 同步 | 异步 |
是否阻塞redis其它命令 | 是 | 否(在生成子进程执行调用fork函 数时会有短暂阻塞) |
复杂度 | O(n) | O(n) |
优点 | 不会消耗额外内存 | 不阻塞客户端命令 |
缺点 |
会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止 |
需要fork创建子进程,消耗内存,RDB持久化过程由子进程负责,会在后台异步进行快照操作,快照同时还可以响应客户端请求 |
配置自动生成rdb文件后台使用的是bgsave方式;
缺点
- 每次快照是一次全量备份,fork子进程进行后台操作,子进程存在开销;
- 在快照持久化期间修改的数据不会被保存,可能丢失数据;
AOF(append-only file)
如果Redis 因为某些原因而造成故障停机,那么服务器将丢失最近写入、且仍未保存到快照中的那些数据,从 1.1 版本开始,Redis 增加了一种完全耐久的持久化方式: AOF 持久化将修改的每一条指令追加文件的方式记录进文件appendonly.aof中, 重启时再重新执行AOF文件中的命令达到恢复数据的目的,写入过程宕机,也不影响之前的数据,可以通过 redis-check-aof检查修复问题;
aof文件存储如下:
$6 SELECT $1 0 *3 $3 set $2 k1 $3 111
上面的是基于RESP协议存储的文本,RESP 协议在Redis1.2被引入,直到Redis2.0才成为和Redis服务器通信的标准;RESP 是一个支持多种数据类型的序列化协议:简单字符串(Simple Strings),错误( Errors),整型( Integers), 大容量字符串(Bulk Strings)和数组(Arrays);
当程序读入这个 AOF 文件时, 它首先执行 SELECT 0
命令 —— 这个 SELECT
命令是由 AOF 写入程序自动生成的, 它确保程序可以将数据还原到正确的数据库上,然后再执行后面的保存的命令;
以星号* 为首字符,接着是表示数组中元素个数的十进制数;
美元符 "\$" 后面跟着组成字符串的字节数(前缀长度);
参考:[https://www.redis.com.cn/topics/protocol.html]
修改配置文件来打开 AOF 功能:
# appendonly yes
加载AOF出错时记录日志
# yes表示如果aof尾部文件出问题,写log记录并继续执行,no表示提示写入等待修复后写入 aof-load-truncated yes
如每当Redis执行一个改变数据集的命令时(比如 set), 这个命令就会被追加到 AOF 文件的末尾,当Redis重新启动时,程序就可以通过重新执行 AOF文件中的命令来达到重建数据集的目的;
配置Redis隔多久进行一次将数据fsync到磁盘如下:
- appendfsync always:每执行一个命令保存一次;每次有新命令追加到 AOF 文件时就执行一次 fsync ;写入和保存都由主进程执行,两个操作都会阻塞主进程,服务器必须阻塞直到命令信息被写入并保存到磁盘之后, 才能继续处理请求;
- appendfsync everysec:每一秒钟保存一次;写入操作由主进程执行,阻塞主进程,保存操作由子线程执行,不直接阻塞主进程,但保存操作完成的快慢会影响写入操作的阻塞时长;
- appendfsync no:不保存;写入和保存都由主进程执行,两个操作都会阻塞主进程,保存操作只会在AOF 关闭或 Redis 关闭时执行, 或者由操作系统触发,系统的写缓存被刷新(可能是缓存已经被写满,或者定期保存操作被执行);
参考:[https://redisbook.readthedocs.io/en/latest/internal/aof.html#id9]
- 测试kill -9杀掉redis进程后,数据是否恢复
保存数据
此时appendonly.aof文件存储如下:
使用kill -9 将redis进程杀掉,docker搭建的使用docker kill命令,之后再重启redis服务;发现数据被恢复回来了,就是从AOF文件中恢复回来的;
AOF破损文件的修复
如果redis在append数据到AOF文件时,机器宕机了,这时候可能会导致AOF文件破损;使用如下命令来修复破损的AOF文件:
redis-check-aof --fix
AOF重写
AOF文件里可能有太多没用指令,所以AOF会定期根据内存的最新数据生成aof文件;
Redis配置AOF自动重写频率:
# auto-aof-rewrite-min-size 64mb //aof文件至少要达到64M才会自动重写,文件太小恢复速度本来就很快,重写的意义不大 # auto-aof-rewrite-percentage 100 //aof文件自上一次重写后文件大小增长了100%则再次触发重写
AOF重写触发条件:[https://redisbook.readthedocs.io/en/latest/internal/aof.html#id14]
AOF可以进行手动重写,进入Redis客户端执行命令bgrewriteaof重写AOF;
Redis启动时,先看是否存在aof文件,若存在则优先选择aof文件恢复数据,因为aof一般来说数据更全一点,若aof不存在,则才会查找rdb是否存在;
参考:[https://redisbook.readthedocs.io/en/latest/internal/aof.html#id13]
混合持久化(Redis 4.x以后的特性)
重启 Redis 时,很少使用 RDB来恢复内存状态,因为会丢失大量数据;通常使用 AOF 日志重写,但是重写AOF日志性能相对 RDB来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间; 为了解决这个问题,Redis 4.0带来了一个新的持久化选项——混合持久化;
通过以下配置可以开启混合持久化:
# aof-use-rdb-preamble yes
开启了混合持久化,在AOF重写时,不再是单纯将内存数据转换为RESP协议的命令写入AOF文件,而是将重写这一刻之前的内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换;
appendonly.aof文件存储如下:
AOF文件上半部分存储的是RDB的数据,下半部分的是AOF的数据;
格式如下:
AOF根据配置规则在后台自动重写aof文件,也可以人为执行命令bgrewriteaof重写AOF;
操作前appendonly.aof文件存储如下:
执行set操作
执行set操作后appendonly.aof文件存储如下:
执行bgrewriteaof操作:
执行bgrewriteaof操作后appendonly.aof文件存储如下:
Redis在重启时,先重写rdb到内存,然后在重写aof到内存,因此重启效率得到提升;后面的修改操作则通过重写增量AOF日志替代之前的AOF全量文件重写;
重启后appendonly.aof文件存储如下: