Redis是内存数据库,它将自己的数据存储在内存里面,一旦Redis服务器进程退出或者运行Redis的服务器停机,Redis中的数据就会丢失。
为了避免数据丢失,所以Redis提供了持久化机制,将存储在内存中的数据保存到磁盘中,用于在Redis服务器进程退出或者运行Redis服务器的计算机停机导致数据丢失时,快速的恢复之前Redis存储在内存中的数据。
Redis提供了2种持久化方式,分别为:
RDB全名为Redis Database Backup file,意为Redis数据库备份文件,也被叫做Redis数据快照。简单来说就是把内存中的所有数据记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。正是由于RDB持久化的这种特性,所以RDB持久化也叫做快照持久化。这个快照文件是一个经过压缩的二进制文件,通过该文件可以还原生成RDB文件时Redis中的数据。
Redis提供了两种命令来创建RDB文件。
这两个命令有一定的区别。
save命令会直接阻塞Redis服务器进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何请求。
bgsave命令则会通过fork创建一个子进程,然后由子进程异步的创建RDB文件,服务器进程(父进程)继续处理命令请求。
因此我们一般更多的使用的是bgsave命令。
同时在Redis的配置文件中,有一个save参数,可以用于设定Redis自动触发bgsave的条件。
默认的配置条件表示,只要满足以下3个条件中的任意1个,BGSAVE命令就会被执行:
服务器在900s(即15分钟)之内,对数据库进行了至少1次修改
服务器在300s(即5分钟)之内,对数据库进行了至少10次修改
服务器在60s(即1分钟)之内,对数据库进行了至少10000次修改
同时也可以设定Redis的备份文件的名称
这里有一个小坑,就是如果你修改完毕dbfilename之后,你再次重启你的Redis你会发现你的数据都消失了,原因是因为Redis会去配置文件中的dbfilename中查找他的RDB文件,根据这个名称去寻找这个文件,如果找到了就从中读取数据进行数据恢复。而由于你修改了这个名称,所以你再次重启的时候Redis发现没有这个文件,因此Redis会创建这个文件,并重新开始向其中记录数据,因此你原有的数据还在dump.rdb这个文件中,只不过新的数据都会记录到新的RDB文件中。
载入RDB文件的目的是为了在Redis服务器进程重新启动之后还原之前存储在Redis中的数据。
并且Redis并没有提供从RDB文件中读取数据的命令,而是每次启动Redis他都会从当前配置文件中对应的RDB文件中进行数据读取,Redis也已经在启动Redis服务的时候告诉你这一点了。
当然,Redis服务器启动时是否会载入RDB文件还取决于服务器是否启用了AOF持久化功能,具体判断逻辑为:
当然,AOF持久化功能默认是关闭的,因此默认情况下Redis都是通过RDB文件来载入数据。
AOF全称为Append Only File(追加文件)。Redis处理的每一个写命令(set,hset等)都会记录在AOF文件中,可以看作是命令日志文件。
AOF功能默认是关闭的,需要通过修改配置文件来开启。
开启 AOF 持久化后每执行一条会更改 Redis 中的数据的命令,Redis 就会将该命令写入到内存缓存 server.aof_buf 中。
AOF的命令记录的频率也是可以配置的,默认为everysec,也就是每秒。
always表示每执行一次写命令都立刻记录到AOF文件中,性能影响大
everysec表示写命令执行完毕之后先放入到AOF缓冲区中,然后每隔1s将缓冲区中的文件写入到AOF中,最多丢失1s数据
no表示写命令执行完毕后先放入AOF缓冲区,由操作系统决定何时将内容写回到磁盘中,可靠性差,可能丢失大量数据
Redis的AOF方式
Redis的AOF重写描述不准确以及一个小错误
appendfsync always #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec #每秒钟同步一次,显式地将多个写命令同步到硬盘
appendfsync no #让操作系统决定何时进行同步
关系型数据库(如 MySQL)通常都是执行命令之前记录日志(方便故障恢复),而 Redis AOF 持久化机制是在执行完命令之后再记录日志。
为什么是在执行完命令之后记录日志呢?
这样也带来了风险(我在前面介绍 AOF 持久化的时候也提到过)
由于AOF是记录命令,因此AOF文件会比RDB文件大得多。而且AOF会记录对同一个key的多次写操作,即使其实只有最后一次写操作有意义。通过bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到一样的效果。
例如对同一个name的操作,使用bgrewriteaof之后,本来记录三次的命令,直接会变成记录最后一次的命令。
set name 123
set name 234
set name 345
---bgrewriteaof----
set name 345
上面我已经说过,AOF的文件会比RDB文件大得多,所以,AOF提供了一种重写机制。
当 AOF 变得太大时,Redis 能够在后台自动重写 AOF 产生一个新的 AOF 文件,这个新的 AOF 文件和原有的 AOF 文件所保存的数据库状态一样,但体积更小。
AOF 重写是一个有歧义的名字,该功能是通过读取数据库中的键值对来实现的,程序无须对现有 AOF 文件进行任何读入、分析或者写入操作。
在执行 BGREWRITEAOF 命令时,Redis 服务器会维护一个 AOF 重写缓冲区,该缓冲区会在子进程创建新 AOF 文件期间,记录服务器执行的所有写命令。当子进程完成创建新 AOF 文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新 AOF 文件的末尾,使得新的 AOF 文件保存的数据库状态与现有的数据库状态一致。
最后,服务器用新的 AOF 文件替换旧的 AOF 文件,以此来完成 AOF 文件重写操作。
Redis 7.0 版本之前,如果在重写期间有写入命令,AOF 可能会使用大量内存,重写期间到达的所有写入命令都会写入磁盘两次。
当然,Redis也会在触发阈值时自动去重写AOF文件,阈值也可以在redis.conf中进行配置
第一个参数表示AOF文件比上次文件增长超过百分之多少之后进行重写
第二个参数表示AOF文件体积最小多大以上才能触发重写
简而言之,Redis的AOF文件重写功能,是通过Redis服务器创建一个新的AOF文件来替代现有的AOF文件,新旧两个AOF文件所保存的数据库数据相同,但新AOF文件不会包含任何浪费空间的冗余命令,所以新AOF文件的体积通常会比旧AOF文件的体积要小很多。
而AOF文件的重写是如何实现的现在来举个例子:
因为AOF文件包含了重建数据库所需的所有写命令,所以Redis服务器只要读入并重新执行一遍AOF文件里面保存的写命令,就可以还原Redis服务器关闭之前的数据。
Redis读取AOF文件并还原数据库的详细步骤如下:
上面这个操作无非就是向一个数组添加先添加了 1 2 3,然后再出来3和2,然后又插入4 5,最终arrays中数据为1 4 5,那么我们只要lpush 5 4 1(rpush 1 4 5)即可,那么就一下子把多余的几条命令给去除了。
因为AOF文件包含了重建数据库所需的所有写命令,所以Redis服务器只要读入并重新执行一遍AOF文件里面保存的写命令,就可以还原Redis服务器关闭之前的数据。
Redis读取AOF文件并还原数据库的详细步骤如下:
如果Redis开启了AOF持久化功能,那么Redis服务器在启动的时候就会载入AOF文件。
因为AOF文件重写会进行大量的文件写入操作,所以执行这个操作的线程将被长时间阻塞。
因为Redis服务器使用单个线程来处理命令请求,所以如果由服务器进程直接执行这个操作,那么在重写AOF文件期间,服务器将无法处理客户端发送过来的命令请求。
为了避免上述问题,Redis将AOF文件重写功能放到子进程里执行,这样做有以下2个好处:
AOF后台重写的步骤如下所示:
持久化方式:
RDB定时对整个内存做快照,
AOF记录每一次执行的命令
数据完整性:
RDB不完整,两次备份之间会丢失,
AOF相对完整,取决于刷盘策略
文件大小:
RDB有压缩,文件体积小,
AOF记录命令,文件体积大
宕机恢复速度:
RDB很快
AOF慢
数据恢复优先级:
RDB低,因为数据完整性不如AOF
AOF,高,因为数据完整性更高
系统资源占用:
RDB高,大量CPU和内存的消耗,
AOF低,主要是磁盘IO资源,但AOF重写时会占用大量CPU和内存资源
使用场景:
RDB使用于可以容忍数分钟的数据丢失,追求赶快的启动速度的场景。
AOF使用于对数据安全性要求较高的场景。
关于 RDB 和 AOF 的优缺点,官网上面也给了比较详细的说明。
官网说明
这里结合自己的理解简单总结一下。
RDB 比 AOF 优秀的地方 :
AOF 比 RDB 优秀的地方 :
由于 RDB 和 AOF 各有优势,于是,Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 aof-use-rdb-preamble 开启)。
如果把混合持久化打开,AOF 重写的时候就直接把 RDB 的内容写到 AOF 文件开头。
这样做的好处是可以结合 RDB 和 AOF 的优点, 快速加载同时避免丢失过多的数据。当然缺点也是有的, AOF 里面的 RDB 部分是压缩格式不再是 AOF 格式,可读性较差。
官方文档的描述