点击上方“蓝字”关注我们
Redis 提供了不同级别的持久化方式:
RDB是一种文件后缀名,这种持久化方案的名称也由此而来。RDB持久化既可以手动执行,也可以根据服务器配置选项定制执行,该功能可以将某个时间点上的数据库状态保存到一个RDB文件中。RDB持久化生成的RDB文件是一个经过压缩的二进制文件。
RDB文件的载入是在启动的时候自动执行的,并没有专门用于载入RDB文件的命令。
当redis服务器启动时,用户可以通过指定配置文件或者传入启动参数的方式设置save选项,如果没有设置,默认为:
save 900 1
save 300 10
save 60 10000
第一行意思是服务器在900秒之内,对数据库进行了至少1次修改。且满足三个条件中任意一个,就会触发BGSAVE操作。
全拼为append only file。与RDB持久化通过保存数据库中的键值对记录数据库状态不同,AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的,也就是传统的追加日志的方式。
AOF文件的更新频率通常比RDB文件的更新频率高,所以如果开启了AOF持久化功能,那么服务器会优先使用AOF文件来还原数据库状态;且只有在AOF关闭的时候,才使用RDB文件;
AOF持久化功能的实现可以分为三个步骤:
当AOF持久化命令打开的时候,服务器在执行完一个写命令的之后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾;
Redis服务器是一个单Reactor单线程模型,可以理解为有一个线程一直在循环处理各种事件。伪代码:
def eventLoop():
while True:
# 处理连接事件,接收命令请求以及发送命令回复
# 处理命令请求时可能会有新内容被追加到aof_buf缓冲区中
# 处理时间事件
processTimeEvents()
# 考虑是否要将aof_buf中的内容写入和保存到AOF文件里面
flushAppendonlyFile()
flushAppendonlyFile函数的行为由服务器配置的appendfsync选项的值来决定,各个不同值产生的行为:
在现在操作系统中,当用户调用write函数将数据写入到文件的时候,操作系统通常会将写入数据暂时保存在一个内存缓冲区里面(这个地方和aof_buf不同,这个是操作系统层面的)。等到缓冲区被填满、或者超过了指定的时限之后,才真正地将缓冲区中的数据写入到磁盘里面。这会提高效率,但也会带来安全问题,因为一旦计算机停机,那么没有被写入磁盘的数据将丢失。所以系统提供了fsync和fdatasync两个同步函数,可以强制操作系统立即将缓冲区中的数据同步到磁盘。
了解了这个概念后再看appendfsync:
对于redis服务的每个事件循环都需要同步到磁盘,效率是最低的,但是安全系数也最高。最多也只会丢失一个事件循环中所产生的命令数据。
一图胜千言,不再赘述。
因为AOF持久化是对所有的写操作进行记录,会造成文件文件越来越大,不加控制的话,可能会对整个服务器产生影响。
为了解决AOF文件体积膨胀的问题,Redis提供了AOF文件重写(rewrite)功能,即BGREWRITEAOF命令。通过该功能,Redis可以创建一个新的AOF文件来代替原AOF文件,新旧AOF文件所表示的数据库状态相同,不同的是新文件通过删掉冗余命令包括已经失效的命令,减小了AOF体积。例如:对同一个String类型的多次复制,只需要保存最后一个就可以了。
AOF重写并不需要对原AOF文件进行读写,而是直接通过一个子进程读取数据库状态然后反编译出redis命令来实现的。通过子进程而不是主进程来处理重写,主要是为了防止长时间的重写阻塞主进程,但是这又会带来一致性问题:因为重写期间,redis还在提供服务,还在有数据的修改和写入。为了解决这种一致性问题,Redis服务器设置了一个AOF重写缓冲区,当重写开始时,新来的Redis写命令会同时写入AOF缓冲区、AOF重写缓冲区,如下图
这还不够,当子进程完成AOF重写工作之后,它会向父进程发送一个信号,①通知父进程将AOF重写缓冲区中的所有内容写入新的AOF文件中,并且②对新的AOF文件进行改名;此处只有这2个操作会阻塞父进程,也是为了防止一致性问题,且将对整个服务器的性能损耗降到了最低。
以上,就是aof重写的全部逻辑,很巧妙的使用了写时复制机制。
AOF优点
AOF缺点