如果没有持久化的话,redis 遇到灾难性故障的时候,就会丢失所有的数据
通过持久化将数据存在磁盘上,然后可以定期同步和备份这些文件到云存储服务上去,那么就可以保证数据不丢失
redis 集群架构是用来支撑海量数据、高并发、高可用,持久化主要是做灾难恢复、数据恢复,也可以归类到高可用的一个环节里面去
对 redis 中的数据执行周期性的持久化,如下图
AOF机制对每条写入命令作为日志,以append-only的模式写入一个日志文件中,在redis重启的时候,可以通过回放AOF日志中的写入指令来重新构建整个数据集
为了保证性能,会先写入 os cache 中,然后定期强制执行 fsync 操作将数据刷入磁盘
它的原理:
rewrite操作示意图如上, aof 不断被追加,内存中数据有最大限制会自动淘汰,当 aof 中的数据大于内存中数据时,就会执行 rewrite 操作,生成新的 aof 文件
AOF 机制对每条写入命令作为日志,以 append-only 的模式写入一个日志文件中,在 redis 重启的时候,可以通过回放 AOF 日志中的写入指令来重新构建整个数据集
/etc/redis/6379.conf
save 900 1
save 300 10
save 60 10000
以上内容是原始默认的配置,该功能叫做 SNAPSHOTTING(快照)
save <seconds> <changes>
:当 n 秒后有 n 个 key 发生改变,就做一次快照备份
也可以手动调用save或者bgsave命令,同步或异步执行rdb快照生成
save可以设置多个snapshotting检查点,默认设置了 3 个检查点,每到一个检查点,就会去check一下,是否有指定的key数量发生了变更,如果有,就生成一个新的dump.rdb文件
每次生成一个新的快照,都会覆盖之前的老快照,所以只会有一个 dump.rdb
思路:
下面使用命令来实验
redis-cli
set k1 11
set k2 22
set k3 33
exit
redis-cli shutdown
# 启动 redis
cd /etc/init.d/
./redis_6379 start
# 进入 cli 查看数据是否还存在
redis-cli
get k1
get k2
实验证明数据还是存在的。因为是 redis 自带的停止工具,是一种安全的退出模式,会将内存中的数据立即生成一份 rdb 快照文件,该文件存储在 /var/redis/6379/dump.rdb 中
下面再来测试 2 种非安全的退出模式:
第一种,写入几条数据,然后直接 kill 掉 redis 进程,启动后会发现数据丢失了
第二种
TIP 在非正常退出 redis 的时候,再次启动会报错 [root@eshop-cache01 init.d]# ./redis_6379 start /var/run/redis_6379.pid exists, process is already running or crashed 由此可以看出来,当 redis 启动的时候回生成一个 pid 文件,如果该文件存在则不能再次启动 这里只能先删除该 pid 文件后,才能启动 redis 了
AOF 持久化默认是关闭的,RDB 是默认开启的
打开需要修改/etc/redis/6379.conf 中的 APPEND ONLY MODE 配置区:
打开 AOF 持久化机制之后,redis 每次接收到一条写命令,先写入 os cache 的,然后每隔一定时间再 fsync 一下,就会写入磁盘的日志文件中
appendonly yes
启用后 appendfsync 属性开始生效,有三个策略可选
原理:/var/redis/6379 该路径下,是之前配置的路径,文件内容如下,操作是写入了一条 set mykey1 123k 命令。
[root@eshop-cache01 6379]# cat appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$6
mykey1
$4
123k
redis 中的数据其实有限的,很多数据可能会自动过期,可能会被用户删除,可能会被 redis 用缓存清除的算法清理掉,总之 redis 中的数据会不断淘汰掉旧的,就一部分常用的数据会被自动保留在 redis 内存中
所以可能很多之前的已经被清理掉的数据,对应的写日志还停留在 AOF 中,AOF 日志文件就一个,会不断的膨胀到很大
所以 AOF 会自动在后台每隔一定时间做 rewrite 操作,比如日志里已经存放了针对 100w 数据的写日志了; redis 内存中只剩下 10 万; 基于内存中当前的 10 万数据构建一套最新的日志,到 AOF 中; 覆盖之前的老日志; 确保 AOF 日志文件不会过大,保持跟 redis 内存数据量一致
redis 2.4 之前,还需要手动,开发一些脚本 crontab 定时通过 BGREWRITEAOF 命令去执行 AOF rewrite,但是 redis 2.4 之后,会自动进行 rewrite 操作
aof rewrite 有两个重要的配置参数
/etc/redis/6379.conf
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
上面的配置意思是: 当 aof 日志超过 64 m ,且增长的比例超过了之前的100%,比如之前是 60 m,那么当文件增长到 120 m 的时候,就会触发 rewrite 操作
rewrite 流程
下图对上面文字描述的演示
如果 redis 在 append 数据到 AOF 文件时,机器宕机了,可能会导致 AOF 文件破损
可以用 redis-check-aof --fix 命令来修复破损的 AOF 文件(该命令在 redis 安装目录下)
redis-check-aof --fix xxx.aof
可以手动以破坏,然后执行修复:
修复的原理就是删除掉破损的数据,将有缺失的一整条命令删除掉,保留完整的其他命令。
在有 rdb 的 dump 和 aof 的 appendonly 的同时,rdb 里也有部分数据,aof 里也有部分数据,这个时候其实会发现,rdb 的数据不会恢复到内存中
同时存在的时候,会优先使用 aof 文件恢复数据。
数据恢复完全是依赖于底层的磁盘的持久化的,如果 rdb 和 aof 上都没有数据,那就没了
RDB 非常适合做冷备,每次生成之后,就不会再有修改了
数据备份方案:写 crontab 定时调度脚本去做数据备份
每次 copy 备份的时候,都把太旧的备份给删了
这里在 /usr/local/redis 目录下完成这个备份实验
按小时级备份
在 copy/redis_rdb_copy_daily.sh
授权:chmod 777 redis_rdb_copy_hourly.sh
#!/bin/sh
# 生成小时级的文件夹名称 2021022021
cur_date=`date +%Y%m%d%k`
# 以防万一,先删除,再创建目录
rm -rf /usr/local/redis/snapshotting/$cur_date
# -p 可以创建多级目录
mkdir -p /usr/local/redis/snapshotting/$cur_date
cp /var/redis/6379/dump.rdb /usr/local/redis/snapshotting/$cur_date
# 删除48 小时前的目录 2021021821
del_date=`date -d -48hour +%Y%m%d%k`
rm -rf /usr/local/redis/snapshotting/$del_date
# 该命令打开的是一个列表,有多条调度任务就一行一个
crontab -e
# 每小时/每天/每月/每周 第0分钟,也就是每小时执行一次该脚本
0 * * * * sh /usr/local/redis/copy/redis_rdb_copy_hourly.sh
按天备份
与前面的脚本一样,只是时间表达式不一样
在 copy/redis_rdb_copy_daily.sh
#!/bin/sh
# 生成文件夹名称 20190320
cur_date=`date +%Y%m%d`
# 以防万一,先删除,再创建目录
rm -rf /usr/local/redis/snapshotting/$cur_date
# -p 可以创建多级目录
mkdir -p /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
# 该命令打开的是一个列表,有多条调度任务就一行一个
crontab -e
# 每小时/每天/每月/每周,也就是每小时执行一次该脚本
0 * * * * sh /usr/local/redis/copy/redis_rdb_copy_hourly.sh
# 每天0点0分执行一次
0 0 * * * sh /usr/local/redis/copy/redis_rdb_copy_daily.sh
这里讲解几个场景下的数据恢复方案
1、如果是 redis 进程挂掉
那么重启 redis 进程即可,直接基于 AOF 日志文件恢复数据
2、如果是 redis 进程所在机器挂掉
那么重启机器后,尝试重启 redis 进程,尝试直接基于 AOF 日志文件进行数据恢复
因为AOF append-only是顺序写入,如果 AOF 文件破损,那么用 redis-check-aof fix修复
3、如果 redis 当前最新的 AOF 和 RDB 文件出现了丢失/损坏
那么可以尝试基于该机器上当前的某个最新的 RDB 数据副本进行数据恢复
4、如果当前最新的 AOF 和 RDB 文件都出现了丢失/损坏到无法恢复
模拟数据恢复-错误的做法:停止 redis之后,先删除 appendonly.aof,然后将我们的 dump.rdb 拷贝过去,然后再重启 redis,这个时候其实不会恢复 dump.rdb 的数据,因为我们开启了 aof,当 aof 不存在的时候,也不会主动去用 dump.rdb 去恢复数据
正确的做法:停止 redis,关闭 aof,拷贝 rdb 备份,重启 redis,确认数据恢复, 直接在命令行热修改 redis 配置,打开 aof,这个 redis 就会将内存中的数据对应的日志,写入 aof 文件中
热修改命令:redis config set appendonly yes
切记不要停止 redis ,修改配置文件为 yes ,再启动 redis。因为这个时候 aof 文件没有生成的话,数据就又会没有的
5、如果当前机器上的所有 RDB 文件全部损坏
那么从远程的云服务上拉取最新的 RDB 快照回来恢复数据
6、如果是发现有重大的数据错误,比如某个小时上线的程序一下子将数据全部污染了,数据全错了 那么可以选择某个更早的时间点,对数据进行恢复
举个例子,12 点上线了代码,发现代码有 bug,导致代码生成的所有的缓存数据,写入 redis,全部错了,那么你应该找到一份 11 点的 rdb 的冷备,然后按照上面的步骤,去恢复到 11 点的数据,就可以了
参考:
https://zq99299.github.io/note-book/cache-pdp/redis/011.html
https://zq99299.github.io/note-book/cache-pdp/redis/012.html
https://zq99299.github.io/note-book/cache-pdp/redis/013.html