我们知道Redis的数据都是在内存中操作的,而持久化技术就是将内存中的数据写入到硬盘中进行存储。
Redis主要使用两种持久化技术,分别是RDB和AOF,其中RDB的原理是记录当前Redis快照,然后恢复数据时使用快照进行恢复。而AOF则是将对Redis的所有操作语句记录在一个日志文件中,在恢复时执行所有的语句就可以将Redis恢复到之前的状态。
在指定时间间隔,执行数据集的时间点快照。实现类似照片记录效果方式,就是把某一个时刻的数据和状态以文件的形式写到磁盘上,也就是快照。这样一来即使故障宕机,快照文件也不会丢失,数据的可靠性得到了保障。这个快照文件就称为RDB文件(dump.rdb)。
Redis 6.0.16以下版本,使用自动触发。在Redis.conf配置文件的SNAPSHOTTING下配置save参数,来触发Redis的RDB持久化条件,比如save m n
表示m秒内数据存在n次修改,自动触发bgsave
命令。
Redis6.2 以及Redis-7.0.0以上版本对RDB进行了调整,主要是对存储频率进行了修改。
对于RDB持久化,有两种方式,分别是自动触发和手动触发。首先我们讲自动触发。
Redis 7版本中有配置redis.conf有save <seconds> <changes>命令。
save 5 2 #表示5或有2次修改就触发持久化
dir /usr/local/redis_dump
3. 指定dump文件的名字
dbfilename dump6379.rdb
4. 查看config配置
config get dir
5. 触发备份
在5s内执行两次插入操作
set k1 v1
set k2 v2
可以发现dump文件成功生成了
6. 使用dump文件进行数据库恢复
实现恢复,我们只需要将备份文件移动到redis的安装目录并启动服务即可
首先我们使用flushdb
清空redis,看看是否可以恢复数据(在这之前我们将之前的dump文件改一个名字)
此时我们重启redis服务,发现数据并没有恢复,这是因为flushall/flushdb命令也会产生dump.rdb文件,但里面是空的,是没有实际意义的,如下图发现有两个dump文件了
手动删除自动生成的dump文件
rm -rf dump6379.rdb
然后使用shutdown命令管理redis-cli客户端,此时发现又多了一个dump文件
这是因为当我们关闭redis-cli时,redis会自动将我们把数据库最新的快照给保存起来
现在我们继续把这个dump文件删除,然后把之前的dump文件的名字改回来
mv dump6379.rdb.bak dump6379.rdb
重启redis服务,观察数据有没有恢复,可以发现数据全部恢复过来了。
我们可以使用save
或bgsave
来实现redis备份的手动触发(常用的场景是一些重要数据需要备份,但又没有达到自动备份的条件,此时我们需要进行手动备份)
redis提供了save
和bgsave
两个命令来生成RDB文件,两个命令的区别是,save命令在主程序中会阻塞当前的redis服务器,知道持久化工作完成,在执行redis期间,redis不能处理其它命令,线上禁止使用
。bgsave执行时,redis会在后台异步进行快照操作,不阻塞块照同时还可以响应客户端请求,该触发方式会fork一个子进程由子进程复制持久化过程。下面测试一下bgsave的使用方法。
首先我们删除路径下的所有备份文件,然后执行bagsave命令
bgsave
可以发现已经成功备份了
我们还可以通过lastsave
命令获取最近一次成功执行快照的时间
禁止快照有两种方式:
redis-cli config set save ""
save ""
在redis配置文件snapshotting模块,有如下配置项:
save <seconds> <changes>
dbfilename
dir
stop-writes-on-bgsave-error
stop-writes-on-bgsave-error
rdbcompression
rdbchecksum
rdb-del-sync-files
stop-writes-on-bgsave-error yes
默认为yes,如果配置成no,表示你不在乎数据不一致或者有其他手段发现和控制这种不一致,那么在快照写入失败时,也能确保redis继续接受新的写请求。
rdbcompression yes
默认为yes,对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗cpu来进行压缩的话,可以设置为关闭此功能。
rdbchecksum yes
默认为yes,在存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能
rdb-del-sync-files no
默认为no,此选项常用在redis主从复制的时候,在么有持久的情况下删除复制中使用RDB文件启用。
AOF以日志的形式来记录每个写操作,将redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重写构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次完成数据的恢复工作。
默认情况下,redis是没有开启AOF(append only file)的。开启AOF功能需要设置配置: appendonly yes
快照不是很耐用。如果您运行Redis的计算机停止,您的电源线出现故障,或者您意外kill -9您的实例,则写入Redis的最新数据将丢失。虽然这对某些应用程序来说可能没什么大不了的,但有一些完全耐用性的用例,在这些情况下,仅Redis快照不是一个可行的选择。当我们开启appendonly yes
后,每次Redis收到更改数据集的命令(例如SET)它会将其附加到AOF中。当您重新启动Redis时,它将重新播放AOF以重建状态。
AOF的工作流程大致分为五步:
同步文件的三种写回策略
将命令写入磁盘的AOF文件AOF
重写),从而起到AOF文件压缩的目的Always:同步写回,每个写命令执行完立刻同步地将日志写回磁盘
everysec(默认策略): 每秒写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔1秒把缓冲区的内容写入磁盘
no:操作系统控制的写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓存区写回磁盘
appendonly yes
2. 使用默认写回策略,每秒钟写入
3. 设置AOF文件的保存路径
redis 6中AOF文件的保存位置和RDB保存位置是一样的,都是通过redis.conf配置文件的dir配置。
redis 7会在RDB目录下再创建一个目录 appendonlydir
(这个可以自己指定),再在这个目录下存储AOF文件。
redis 6有且仅有一个AOF文件,叫做 appendonly.aof
redis 7采用了Mult Part AOF设计机制,将aof文件从1个,改为了多个。在MP-AOF中,我们讲AOF分为三种类型
BASE:表示基础AOF,它一般由子进程通过重写产生,该文件最多只有一个
INCR:表示增量AOF,它一般在AOFRW开始执行时被创建,该文件可以存在多个
HISTORY:表示历史AOF,它由BASE和INCR AOF变化而来,每次AOFRW成功完成时,本次AOFRW之前对应的BASE和INCR AOF都会变为HISTORY,HISTORY类型的AOF会被Redis自动删除
为了管理这些AOF文件,引入了一个manifest清单文件来跟踪、管理这些AOF。同时,为了便于AOF备份和拷贝,我们将所有的AOF文件和manifest文件放入一个单独的文件目录中,目录名为appenddirname配置
开启AOF后,我们重启redis-server,然后写入数据观察变化
可以发现在原来的RDB文件目录下,多了一个appendonlydir目录,并且目录里有三个我们说到的AOF文件类型,说明AOF配置成功了。
然后我们分析一下,如果rdb文件和AOF文件都存在,redis会使用哪个文件进行恢复?
cp -r appendonlydir/ appendonlydir.bak
flushdb
然后重新生成了一个rdb文件,再次删除
3. 关闭数据库
shutdown
这里又会生成一个rdb文件,再次删除
发现数据并没有恢复,这是因为flushdb也是一个操作命令,AOF同样会记录下来,所以数据库会再次请空
5. 删除当前AOF文件夹,将之前备份的文件夹恢复过来,再次重启redis-server观察数据有没有恢复(注意rdb文件要删除)
可以发现数据成功恢复了
由于AOF持久化是Redis不断将写命令记录到AOF中,随着redis不断的进行,AOF的文件会越来越大,文件越大,占用服务器内存越大以及AOF恢复要求时间越长。为了解决这个问题,Redis新增了重写机制,当AOF文件的大小超过所设定的峰值时,Redis就会自动启动AOF文件的内容压缩。只保留可以恢复数据的最小指令集,当然,我们也可以通过手动命令bgrewriteaof
来重写。
配置一下命令:
# 根据上次重写的aof大小,判断当前aof大小是不是增长了100%(1倍)
auto-aof-rewrite-percentga 100
# 重写时文件大小要达到64mb
auto-aof-rewrite-min-size 64mb
只有上面两个配置同时满足才会触发AOF得重写机制。
那么AOF是怎么重写的,举个例子,加入AOF记录了下面这三条命令:
set k1 v1
set k1 v2
set k1 v3
实际上只有set k1 v3
是有效的,AOF可以把前面两条删掉。
下面开始案例演示:
#这里触发条件写小一点,以便于演示
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 1k
3. 关闭aof和rdb混合模式
aof-use-rdb-preamble no
set k1 1
#不断执行set k1 111111111111111111111直到incr文件达到1k
set k1 111111111111111111111
到达1k后发现appendonly.aof.1.incr.aof和appendonly.aof.1.base.aof变为了appendonly.aof.2.incr.aof和appendonly.aof.2.base.aof,此时就发生了重写。查看appendonly.aof.1.base.aof文件内容
发现只保留了一条set k1 111111111111命令,进一步说明发生了重写。
上面案例就使用AOF配置对AOF重写进行了自动触发,下面我们使用bgrewriteaof
命令
bgrewriteaof
可以发现文件名发生了变化,说明发生了AOF重写。
AOF文件重写并不是对原文件进行重新整理,而是直接读取服务器现有的键值对,然后用一条命令代替之前记录这个键值对的多条命令,生成一个新的文件去替代原来的AOF文件。
AOF和RDB这两种模式是可以在Redis中共存的,如果我们开启了这个模式,redis启动时会读取AOF文件做数据恢复。
如果同时开启rdb和aof持久化,重启时只会加载aof文件,不会加载rdb文件。
RDB持久化方式能够在指定的时间间隔对你的数据进行快照存储,AOF持久化方法一记录每次对服务器的写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾。
在这种混合模式下,当redis重启的时候会优先载人AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集更完整。并且RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件,那么为什么不只使用AOF?这是因为RDB更适合用于备份数据库(AOF不断变化不好备份),留着rdb作为一个万一的手段。
1.开启混合设置方式
设置aof-use-rdb-preamble
的值为yes
aof-use-rdb-preamble yes
2. 开启后的效果:RDB镜像做全量持久化,AOF做增量持久化
先使用RDB进行快照存储,然后使用AOF持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的RDB记录,这样的话,重启服务的时候会先从RDB和AOF两部分恢复数据,既保证了数据完整性,又提高了数据恢复的性能。简单来说。AOF文件文件包括了RDB头部和AOF混写。
关闭RDB+AOF缓存,不要它们帮我做持久化工作:
- 禁用rdb:
save ""
禁用rdb持久化模式下,我们仍然可以使用命令save、bgsave生成rdb文件- 禁用aof:
appendonly no
禁用aof持久化模式下,我们仍然可以使用命令bgrewriteaof生成aof文件