在上一篇文章中对Redis的两种持久化方式进行了介绍,还介绍了各自的优缺点以及如何选择,这篇文章就介绍一下redis的持久化应该怎么配置,数据恢复应该怎么操作。
1.RDB配置和数据恢复流程
(1).RDB的配置
首先找到redis的配置文件,我的redis装在了centos上,配置文件的目录为:/etc/redis/6379.conf,打开它找到snapshotting。
可以在snapshotting下配置多个save,这个save其实就是检查点,redis可以配置多个检查点,每到一个检查点,就会去check一下,是否有指定的key数量发生了变更,如果有,就生成一个新的dump.rdb文件。当然,我们也可以通过手动调用save或者bgsave命令,同步或异步执行rdb快照生成。
save 900 1:表示每隔900秒如果有1个key发生变化就会生成一个新的rdb文件
save 300 10:表示每隔300秒如果有10个key发生变化就会生成一个新的rdb文件
save 60 10000:表示每隔60秒如果有10000个key发生变化就会生成一个新的rdb文件
save 5 1 是我们为了实验方便设置的一个检查点
(2).RDB持久化机制的工作流程
(a).redis根据配置自己尝试去生成rdb快照文件
(b).fork一个子进程出来
(c).子进程尝试将数据dump到临时的rdb快照文件中
(d).完成rdb快照文件的生成之后,就替换之前的旧的快照文件
同时只有一个dump.rdb,每次生成一个新的快照,都会覆盖之前的老快照。
(3).rdb数据恢复实验
首先我们打开redis-cli存储一些数据(ps:此时我们还没有在redis.conf中添加save 5 1):
现在我们把一些数据都已经放在了redis里面,然后我们shut down redis,并且重启redis:
那么现在就有点奇怪了,我们还没有添加检查点 save 5 1,为什么数据还是在redis中?其实在我们shutdown redis-cli的时候就已经自动生成了一次快照文件了,所以上述操作是安全操作!(那你说个屁!);
好的,我们接下来就不shutdown 而是直接kill -9 来粗暴杀死redis的进程并且删除掉/var/run 下面redis_6379.pid,模拟redis的故障场景:
这时就发现我们刚刚添加的三个值都拿不到了。
然后我们自己手动设置一个检查点:save 5 1到redis的配置文件中。然后再次将刚刚三个值保存到redis中,然后等待五秒,重复上面杀死redis进程的操作,然后在重启redis,现在我们就发现之前的值没有因为redis被杀死而丢失。
好的,以上就是我们使用RDB进行数据恢复的实验,save 5 1这个检查点记得注释掉或者删除,我们没有必要这么频繁的去生成快照。
2.AOF配置和数据恢复流程
(1).AOF的配置
我们在redis的配置文件中搜索appendonly就可以找到aof的相关配置了。
其实redis默认的持久化方式时rdb,rdb是默认打开的,我们要使用aof的话就需要单独打开。
在生产中,aof一般都是要打开的,除非你觉得丢失几分钟的数据无大碍。
设置 appendonly yes 后就打开了aof,打开aof之后,redis每接受到一条命令都会先写入到日志文件中,当然不会直接写到aof文件中,他会先写入到ox cache中,然后每隔一段时间调用操作系统的fsync操作,将os cache中的数据同步到磁盘上的aof文件中。
而且,当rdb和aof同时开启的时候,redis也会优先aof来进行数据恢复,因为aof的数据相对来说比rdb完整。
aof有三种策略供君选择:
appendfsync always:
每次写入一条数据,立即将这个数据对应的写日志fsync到磁盘上去,性能非常非常差,吞吐量很低; 如果说你要求redis里的数据一条都不丢,那就选择此策略。
appendfsync everysec:
每秒将os cache中的数据fsync到磁盘,这个最常用的,生产环境一般都这么配置,性能很高,QPS还是可以上万的。
appendfsync no:
redis 仅仅负责将数据写入os cache就不管了,然后os自己会时不时根据自己的策略将数据刷入磁盘,人为不可控。
(2).aof数据恢复实验
首先我们打开aof的开关,启用aof,然后向redis中添加数据,然后找到aof文件(我的持久化文件放在:/var/redis/6379),aof中按顺序存放指令,如果你知道aof的规则的话是可以读懂的,也就是说,aof文件是可读的。
我使用的策略是everysec,也就是每秒调用一次fsync,redis先将数据写入os cache中,一秒后才调用fsync操作将数据写入磁盘中,数据没有写入磁盘的话是不安全的,也就是说,everysec还是有可能丢失一秒的数据。
我们将redis的进程杀死,看看数据恢复成功了没:
数据成功的被恢复了,redis进程启动的时候,直接就会从appendonly.aof中加载所有的日志,把内存中的数据恢复回来。
(3).aof的rewrite机制
redis中的数据其实有限的,很多数据可能会自动过期,可能会被用户删除,可能会被redis用缓存清除的算法清理掉。redis中的数据会不断淘汰掉旧的,就一部分常用的数据会被自动保留在redis内存中。所以可能很多之前的已经被清理掉的数据,对应的写日志还停留在AOF中,AOF日志文件就一个,会不断的膨胀,变得很大很大。所以AOF会自动在后台每隔一定时间做rewrite操作,比如日志里已经存放了针对100w数据的写日志了; redis内存只剩下10万; 基于内存中当前的10万数据构建一套最新的日志,到AOF中; 覆盖之前的老日志; 确保AOF日志文件不会过大,保持跟redis内存数据量一致。
首先,我们先去配置文件中搜索一下rewrite,可以看看相关的说明。
rewrite的策略我们使用默认的就好,有兴趣的读者可以去研究一下redis的rewrite策略,我在这里就讲一下上图对应的两个参数,这两个参数相对来说比较重要。这两个参数怎么解释呢?比如说上一次AOF rewrite之后,是128mb。然后就会接着128mb继续写AOF的日志,如果发现增长的比例,超过了之前的100%,256mb,就可能会去触发一次rewrite但是此时还要去跟min-size,64mb去比较,256mb > 64mb,才会去触发rewrite。
(4).aof rewrite过程详解
(a).redis fork一个子进程
(b).子进程基于当前内存中的数据,构建日志,开始往一个新的临时的AOF文件中写入日志
(c).redis主进程,接收到client新的写操作之后,在内存中写入日志,同时新的日志也继续写入旧的AOF文件
(d).子进程写完新的日志文件之后,redis主进程将内存中的新日志再次追加到新的AOF文件中
(e).用新的日志文件替换掉旧的日志文件
(5).aof文件破损修复
当redis在append数据到aof文件中的时候,服务器宕机了,那么就可能造成aof文件的损坏,redis提供了相关的工具来修复破损的aof文件。使用redis-check-aof --fix命令来修复破损的AOF文件。
我们来做一个小实验,我们把备份的aof文件copy出来一份,然后更改它,是他破损,然后使用redis的修复工具来修复它。
首先将aof文件copy出来
我们编辑这个文件,然后更改这个文件:
然后使用redis的修复工具修复这个文件:
redis修复工具就会把最后那行多余的指令删除掉。
3.RDB和AOF同时工作
因为redis的持久化操作是非常消耗性能的,那么当他们俩发生冲突的时候会怎么办?
(1)如果RDB在执行snapshotting操作,那么redis不会执行AOF rewrite; 如果redis再执行AOF rewrite,那么就不会执行RDB snapshotting
(2)如果RDB在执行snapshotting,此时用户执行BGREWRITEAOF命令,那么等RDB快照生成之后,才会去执行AOF rewrite
(3)同时有RDB snapshot文件和AOF日志文件,那么redis重启的时候,会优先使用AOF进行数据恢复,因为其中的日志更完整
(4)在有rdb的dump和aof的appendonly的同时,rdb里也有部分数据,aof里也有部分数据,这个时候其实会发现,rdb的数据不会恢复到内存中
大家也可做个小实验,将aof中的数据删除一条(这条数据已经持久化到rdb中),然后用redis的修复工具进行修复,在用这个文件替换aof文件,重启redis,最后会发现rdb中的数据不会被恢复到内存中。
redis的数据恢复完全是依赖于底层的磁盘的持久化的,如果rdb和aof上都没有数据,那就真的没了。
4.在实际项目的使用中,我们应该如何配置和使用呢?
(1).配置策略
在企业级的项目中,我们使用rdb的默认配置也无大碍,即:
save 900 1
save 300 10
save 60 10000
唯一可能要调整的就是 save 60 10000 这个检查点,因为rdb的生成还是比较耗费资源的,如果说低峰期数据量很小,那么也没太大必要。但是如果你要保证RDB最多丢一分钟的数据,那么剩下的就是你自己根据实际情况去配置,到底是一分钟-10000生成rdb,还是说设置成1分钟-1000生成rdb。
aof的话这里推荐把他打开,调用fsync的策略推荐使用everysec,然后根据你项目的实际情况去设置以下两个属性:
auto-aof-rewrite-percentage 100 这个属性改的必要也不是特别的大
auto-aof-rewrite-min-size 64mb 这个根据你的数据量来定
(2).数据备份方案
RDB的话是非常适合做冷备的,每次RDB生成完成之后就不会再修改了,备份的方案可以这样:
(a).写crontab定时调度脚本去做数据备份
(b).每小时都copy一份rdb的备份,到一个目录中去,仅仅保留最近48小时的备份
(c).每天都保留一份当日的rdb的备份,到一个目录中去,仅仅保留最近1个月的备份
(d).每次copy备份的时候,都把太旧的备份给删了
(e).每天晚上将当前服务器上所有的数据备份,发送一份到远程的云服务上去
每小时copy一次备份,删除48小时前的数据
crontab -e
0 * * * * sh /usr/local/redis/copy/redis_rdb_copy_hourly.sh
redis_rdb_copy_hourly.sh
```
#!/bin/sh
cur_date=`date +%Y%m%d%k`
rm -rf /usr/local/redis/snapshotting/$cur_date
mkdir /usr/local/redis/snapshotting/$cur_date
cp /var/redis/6379/dump.rdb /usr/local/redis/snapshotting/$cur_date
del_date=`date -d -48hour +%Y%m%d%k`
rm -rf /usr/local/redis/snapshotting/$del_date
```
每天copy一次备份
crontab -e
0 0 * * * sh /usr/local/redis/copy/redis_rdb_copy_daily.sh
redis_rdb_copy_daily.sh
```
#!/bin/sh
cur_date=`date +%Y%m%d`
rm -rf /usr/local/redis/snapshotting/$cur_date
mkdir /usr/local/redis/snapshotting/$cur_date
cp /var/redis/6379/dump.rdb /usr/local/redis/snapshotting/$cur_date
del_date=`date -d -1month +%Y%m%d`
rm -rf /usr/local/redis/snapshotting/$del_date
```
每天一次将所有数据上传一次到远程的云服务器上去
(3).数据恢复方案
(a).如果是redis进程挂掉,那么重启redis进程即可,直接基于AOF日志文件恢复数据。
(b).如果是redis进程所在机器挂掉,那么重启机器后,尝试重启redis进程,尝试直接基于AOF日志文件进行数据恢复。AOF没有破损,也是可以直接基于AOF恢复的,如果AOF文件出现了破损,则用redis的修复工具修复之后在进行恢复。
(c).如果redis当前最新的AOF和RDB文件出现了丢失/损坏,那么可以尝试基于该机器上当前的某个最新的RDB数据副本进行数据恢复。
(d).如果当前机器上的所有RDB文件全部损坏,那么从远程的云服务上拉取最新的RDB快照回来恢复数据。
(e).如果是发现有重大的数据错误,比如某个小时上线的程序一下子将数据全部污染了,数据全错了,那么可以选择某个更早的时间点,对数据进行恢复。
(4).基于RDB冷备恢复数据
基于rdb冷备其实是有一些小坑的,这里拿出来记录一下,如果你同时打开RDB和AOF,如果你使用的是AOF的冷备去恢复数据,那么很简单,将redis的aof文件替换成你的冷备然后重启redis就行了。
但是要是你使用的是RDB的冷备,你首先要把redis现有的aof文件删掉,然后把rdb文件替换成你的冷备,但是由于你开着aof,所以在aof启动的时候会直接生成一份空的aof文件,而你的RDB冷备会被无视掉,过了一段时间可能会被重写掉。你可能会想,那我们把AOF关掉不就行了吗?我们把AOF关掉,重启redis,确实,RDB的数据会被恢复到redis中,现在数据回来了,但是AOF不能关掉,所以你再次修改配置文件打开AOF重启redis,这时你发现辛辛苦苦恢复的数据又没了,其实还是因为打开AOF重新生成了一份空的AOF文件,RDB里面就算有数据也不会恢复到redis当中。那么怎么解决呢?我们可以通过热修改redis属性的方式进行恢复,我们先把redis的AOF关掉,用RDB冷备恢复数据,在redis-cli 中使用 config set 指令来开启AOF,等RDB冷备的数据全被写入AOF后,再修改配置文件打开AOF,重启redis即可。以下是具体的流程:
(a).停止redis
(b).关闭aof
(c).拷贝rdb备份
(d).重启redis,确认数据恢复
(e).直接在命令行热修改redis配置,打开aof,redis就会将内存中的数据对应的日志,写入aof文件中
(f).此时aof和rdb两份数据文件的数据就同步了