通常数据库存在三种用于持久操作以防止数据损坏的常见策略:
严格上讲Redis为持久化提供了三种方式:
[root@localhost ~]# cd /usr/local/redis/
[root@localhost redis]# ll
total 0
drwxr-xr-x. 2 root root 152 Dec 12 20:58 bin
[root@localhost redis]# mkdir conf
[root@localhost redis]# mkdir data
[root@localhost redis]# mkdir log
[root@localhost redis]# vim /usr/local/redis/conf/redis.conf
配置文件
# 放行访问IP限制
bind 0.0.0.0
# 后台启动
daemonize yes
# 日志存储目录及日志文件名
logfile "/usr/local/redis/log/redis.log"
# rdb数据文件名
dbfilename dump.rdb
# rdb数据文件和aof数据文件的存储目录
dir /usr/local/redis/data
#设置密码
requirepass 123456
[root@localhost redis]# bin/redis-server conf/redis.conf
我们可以配置Redis在n秒内如果超过m个key被修改就自动做快照,下面是默认的快照保存配置(这3个选项都屏蔽,则RDB禁用)∶
# 900秒内如果超过1个key改动,则发起快照保存
save 900 1
# 300秒内如果超过10个key改动,则发起快照保存
save 300 10
# 60秒内如果超过1W个key改动,则发起快照保存
save 60 10000
把整个内存数据映射到硬盘中,保存一份到硬盘,因此恢复数据起来比较快,把数据映射回去即可,不像AOF,一条条的执行操作命令。
快照是默认的持久化方式。这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.db。可以通过配置设置自动做快照持久化的方式。
产生快照的情况有以下几种:
Redis默认会将快照文件存储在Redis当前进程的工作目录中的dump.rdb文件中,可以通过配置dir和dbfilename两个参数分别指定快照文件的存储路径和文件名。流程过程如下(rdb.c中)。
BGSAVE会fork一个子进程来保存RDB,在这个期间能够正常接受外界命令,这时候如果主进程有修改的语句,就会把需要修改的数据复制出来,给子进程使用,主进程改干嘛干嘛。
保存好的新的RDB后,会将新RDB替换旧的RDB。如果期间还有SAVE,或BGSAVE命令执行,会被拒绝,如果有BGREWRITEAOF命令,会在BGSAVE执行结束后再执行。
它也是Redis持久化的重要手段之一,AOF (Append Only File)只追加文件,也就是每次处理完请求命令后都会将此命令追加到aof文件的末尾。而RDB是压缩成二进制等时机开子进程去干这件事。
通过配置进行启动,默认是关闭的。
# 默认appendonly为no
appendonly yes
appendfilename "appendonly.aof"
# RDB文件和AOF文件所在目录
dir /usr/local/redis/data
Redis中提供了3种AOF同步策略:
# 每秒钟同步一次,该策略为AOF的缺省策略
appendfsync everysec
# 每次有数据修改发生时都会写入AOF文件
appendfsync always
# 从不同步。高效但是数据不会主动被持久化
appendfsync no
AOF的频率高的话肯定会对Redis带来性能影响,因为每次都是刷盘操作。跟mysql一样了。Redis每次都是先将命令放到缓冲区,然后根据具体策略(每秒/每条指令/缓冲区满)进行刷盘操作。如果配置的always,那么就是典型阻塞,如果是everysec每秒的话,那么会开一个同步线程去每秒进行刷盘操作,对主线程影响稍小。
AOF文件是一个只进行append操作的日志文件,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。假如一次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们修复问题。
AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此 AoF文件的内容非常容易被人读懂,对文件进行分析( parse)也很轻松。
导出(export)AOF文件也非常简单:举个例子,如果你不小心执行了FLUSHALL
命令,但只要AOF文件未被重写,那么只要停止服务器,移除AQEFA文件未尾的 FLUSHALL命令,并重启Redis,就可以将数据集恢复到FLUSHALL执行之前的状态。
Redis可以在AOF文件体积变得过大时,自动地在后台对AOF进行rewrite。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。
因为Redis在创建新AOF文件的过程中,会继续将命令追加到现有的AOF文件里面,即使重写过程中发生停机,现有的AOF文件也不会丢失。
而一旦新AOF文件创建完毕,Redis 就会从旧AOF 文件切换到新 AOF文件,并开始对新AOF文件进行追加操作。
比如我有业务很简单,就来回delete set同一个key。就这个业务运行了10年,那么aof文件将记录无数个delete k1, set k1。其实都是重复的,但是我aof每次都追加,文件变成了1T大小。这时候Redis宕机了,要恢复,你想想1TB大小的aof文件去恢复,累死了。最主要的是1TB大小只记录了两个命令,所以压缩其实就是来处理这件事的。
rewrite触发条件
# fsync持久化策略
appendfsync everysec
# AOF重写期间是否禁止fsync;如果开启该选项,可以减轻文件重写时CPU和硬盘的负载(尤其是硬盘),但是可能会丢失AOF重写期间的数据;需要在负载和安全性之间进行平衡
no-appendfsync-on-rewrite no
# 当前aof文件大于多少字节后才触发重写
auto-aof-rewrite-min-size 64mb
# 当前写入日志文件的大小超过上一次rewrite之后的文件大小的百分之100时,也就是2倍时触发Rewrite
auto-aof-rewrite-percentage 100
# 如果AOF文件结尾损坏,Redis启动时是否仍载入AOF文件
aof-load-truncated yes
Redis先加载AOF文件来恢复原始数据,因为AOF数据比rdb更完整,但是aof存在潜在的bug,如把错误的操作记录写入了aof,会导出数据恢复失败,所以可以把RDB作为后备数据。
为了考虑性能,可以只在slave上开启RDB,并且15min备份一次,如果为了避免AOF rewite的IO以及阻塞,可以在Redis集群中不开启AOE,靠集群的备份机制来保证可用性,在启动时选取较新的RDB文件,如果集群全部崩溃,会丢失15min前的数据。
Redis4.0开始支持该模式。
解决的问题: Redis在重启时通常是加载AOF文件,但加载速度慢。因为RDB数据不完整,所以加载AOF
开启方式: aof-use-rdb-preamble true
开启后,AOF在重写时会直接读取RDB中的内容。
运行过程:通过bgrwriteaof完成,不同的是当开启混合持久化后
新的AOF文件中,一部分数据来自RDB文件,一部分来自Redis运行过程时的增量数据
当我们开启了混合持久化时,启动Redis依然优先加载aof文件,aof文件加载可能有两种情况如下:
优点:既能快速备份又能避免大量数据丢失
缺点:RDB是压缩格式,AOF在读取它时可读性较差
在Redis 2.2或以上版本,可以在不重启的情况下,从RDB切换到AOF:
cp dump.rdb dump.rdb.bak
执行以下两条命令:
# 开启aof
redis-cli config set appendonly yes
# 关闭rdb
redis-cli config set save ""
开启RDB持久化
save 900 1
save 300 10
save 60 10000
开启AOF配置
# 开启aof
appendonly yes
appendfilename "appendony.aof"
# rewrite
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# appendfsync always
appendfsync everysec
# appendfsync no
RDB日志备份,编写脚本定时备份
vim一个redis-rdb-copy-per-hour.sh
#!bin/bash
cur_date=$(date "+%Y%m%d%H%M%S")
rm -rf /usr/local/redis/snapshotting/$cur_date
mkdir -p /usr/local/redis/snapshotting/$cur_date
cp /usr/local/redis/data/dump.rdb /usr/local/redis/snapshotting/$cur_date
del_date=$(date -d -48hour "+%Y%m%d%H%M")
rm -rf /usr/local/redis/snapshotting/$del_date
使用crontab定时器执行备份脚本
crontab -e
然后写入生产环境可以调整一下每小时执行一次