故障恢复
,如果一切都按我们想象的去发展,就可以不存在什么持久化;往往事与愿违,你越不想发生的事情偏偏他就发生了。上面有说到,持久化的核心作用是为了故障恢复,既然redis可能故障,机器同样也会故障;就算是数据落到磁盘了,同样也可能因为磁盘故障,导致数据丢失;如上图!为了做好一个企业级的持久化方案,我们需要将持久化文件定期同步到云端或者远端的服务器,做好分布式存储,来防止因为机器故障带来的灾难性数据丢失。
Redis官方提供了两种持久化方式,快照(RDB)
和AOF日志
,默认情况下,Redis是开启的RDB,关闭了AOF。
什么是快照?
快照其实就是一次全量备份,其数据是以二进制二进制序列化的形式存储;快照持久化可能产生的问题?
Redis是一个单线程程序,此线程需要处理客户端的读写请求,同时还得处理程序内部的逻辑读写;当Redis需要进行持久化的时候,必定就会产生IO操作,IO是比较耗时、耗性能且IO操作又不能使用多路复用;还有个更严重的问题就是,Redis在持久化的时候,数据可能还在发生变化,比如,一个大key,持久化了一半,结果客户端把他给改了,那这会儿该怎么办?是同步,还是不同步?Redis如何解决快照问题?
Redis使用操作系统的COW
(Copy on Write)机制来实现快照持久化,持久化触发会调用glibc的函数fork一个子进程
,然后持久化的操作全部交由子进程去完成,父进程继续执行来自客户端的请求;如上图,子进程产生的时候,和父进程共享内存
中的代码段
和数据段
;linux的机制为了节约内存资源,尽可能的将他们共享,因此,子进程产生的时候,几乎不会带来内存增长;当主进程发生写数据的时候,其实也就是对某一页的数据进行修改,因此会Copy出一份相同的数据
,然后对复制出来的那一页进行修改,子进程看到的数据依然还是原来的那份;这样主进程的操作不会受到影响,子教程同样也不用担心数据会发生变化了,当他产生的那一瞬间,数据相当于凝固了,这样他就可以安安心心的进行序列化并持久了。数据持久化的操作很快,就算是这个期间来了大量的写操作,也最多只会增加原来2倍
(所有页都被copy了一份)的空间
// save <seconds> <changes>
// 检查规则为 时间范围生成的数据变化次数
// 默认redis为以下的检查点;每一分钟有10000个key发生变化,就持久化一次,其他同理
save
save
save
快照文件保存的位置
// 可以通过conf的dir参数进行配置路径
dir /var/redis//data/ (根据自己情况选择合适的路径)
// 同步持久化
save
// 异步持久化
bgsave
冷备方案
;定期将这个文件复制备份到其他服务器,防止数据丢失所有写操作的一份日志记录文件
;当需要对数据进行恢复的时候,就把整份日志进行回放,即可完成整个的数据恢复;当Redis收到客户端的写操作之后,经过参数校验,逻辑处理,没有问题之后会将指令写到AOF日志;也就是说,整个过程是先执行指令,再写日志;// 手动rewrite的指令
bgrewriteaof
// 可以在redis.conf文件中通过以下参数配置rewrite策略
// 表示当前的AOF文件相比与上次rewrite之后的大小增加了百分之多少,默认是100%
// 如上一次rewrite后是100M,当大小超过200M之后就会触发rewrite
auto-aof-rewrite-percentage
// 上面的参数触发之后,还需要和这个参数进行比较
// 比如上一次rewrite之后AOF文件之后10M,当达到20M后上面条件会触发
// 但是他总的大小依然小于最小值64M 所以不会触发rewrite
auto-aof-rewrite-min-size mb
appendfsync
方式设置appendfsync everysec
// 该参数有三个值
// 1. always 就是上面所说的,每次写操作刷一次磁盘,他可能保证数据不丢失,但是性能很差
// 2. everysec(默认) Redis每一秒刷一次磁盘
// 3. no 标识Redis不执行刷磁盘的操作,只是将数据写到OS Cache中,具体什么时候刷磁盘由操作系统决定
基于RDB和AOF各自优缺点,企业级的持久化策略不能仅仅使用RDB,也不能单纯使用AOF;因为RDB可能造成更多的数据丢失,AOF不太适合做冷备、数据恢复较慢、容易出Bug,因此,常用的策略就是两种方案共同使用;既能保证数据尽可能少的丢失,同样又有一个非常好的冷备方案;在特定业务场景或者特定业务,可以考虑只选用其中的一种,这个就属于特例了。
// redis.conf(/etc/redis/6379.conf)中的appendonly参数设置为yes
// 注意,这里只是针对新安装
appendonly yes
特别提醒
!特别提醒
!特别提醒
!不要和新装一样直接修改配置文件开启,数据会丢的
!数据会丢的
!数据会丢的
!)config set appendonly yes
appendonly
yes
redis-cli shutdown
cd /etc/init.d
./redis_6379 start
这里的冷备是基于RDB的dump.rdb文件进行,通过脚本,定时将dump.rdb拷贝到其他机器
// 创建两个目录
// 用于保存缓存文件
mkdir -p /var/redis/6379/cache
// 用于保存脚本
mkdir -p /var/redis/6379/copy
cd /var/redis/6379/copy
创建按小时备份的脚本 vim redis_rdb_copy_hourly.sh
#!/bin/sh
# 生成一个按小时的变量 作为备份的文件名
cur_date=`date +%Y%m%d%k`
rm -rf /var/redis/6379/cache/$cur_date
mkdir -p /var/redis/6379/cache/$cur_date
cp /var/redis/6379/data/dump.rdb /var/redis/6379/cache/$cur_date
# 删除48小时前的备份
del_date=`date -d -48hour +%Y%m%d%k`
rm -rf /var/redis/6379/cache/$del_date
配置定时任务,按小时执行
crontab -e
// 添加以下配置
* * * * sh /var/redis//copy/redis_rdb_copy_hourly.sh
手动执行查看效果
sh /var/redis//copy/redis_rdb_copy_hourly.sh
cd /var/redis//cache/
ll
// 发现已经成功执行并备份了
// 默认情况下 持久化的第一个检查点在5分钟,因此我们保存数据之后通过kill -9 暴力杀死进程
redis-cli
set a
set b
get a
get b
// shutdown会自动做数据持久化并优雅关闭
redis-cli shutdown
// 修改redis配置文件
vim /etc/redis/.conf
// 配置一个5秒有1条数据发送变化就做持久化的策略
save
// 重启redis
redis-cli shutdown
cd /etc/init.d
./redis_6379 start
//做上面相关的测试
基于AOF+RDB的容灾演练 当我们开启了AOF+RDB,在数据恢复的时候,默认使用的AOF进行
// 当我们执行插入一个c=3的key
set c
// 查看aof文件,发现已经保存了相关的日志
再次启动,发现数据依然存在
基于AOF+RDB数据回滚恢复 回滚数据的操作和存在数据中途开启AOF的操作几乎相关 误删数据的容灾恢复
FLUSHDB
redis-cli shutdown
// 保存持久化文件的目录
cd /var/redis//data
vim appendonly.aof
// 删掉最后的 FLUSHDB指令
redis-check-aof appendonly.aof
redis-cli
get a
// 发现数据已经恢复
第一步,将redis服务关闭
redis-cli shutdown
第二步,关闭AOF 将redis.conf
appendonly no
第三步,找到要恢复的dump.rdb冷备文件 将其拷贝到数据保存目录
第四步,备份最新aof配置文件(防止后续的操作失败,还可以基于它恢复)
第五步,启动redis服务并通过redis-cli连接服务
第六步,通过设置临时参数开启aof
config set appendonly yes
// 确保基于最新的redis数据成功了appendonly.aof文件
第七步,修改配置文件,开启AOF
appendonly yes
重启redis
redis-cli
cd /etc/init.d
./redis_6379 start