admin管理员组

文章数量:1794759

Redis持久化策略——AOF重写优化原理

Redis的持久化方式一共分为RDB持久化与AOF持久化,RDB持久化主要保存数据库状态,即最后数据库中保存的值,而AOF持久化保存的是操作数据库的指令,这时两者的区别就很显而易见,RDB持久化只需要保存很小一部分的值,但是AOF持久化要保存对应的所有操作,而每条Redis操作指令还会被进行加工处理,可想而知,如果要完整保存对数据库表的所有操作,那么这个持久化文件的体积将会很庞大,因此设计者设计过程中实现了AOF重写的优化,本文旨在一步步推进讲解AOF的重写优化策略。

AOF重写实现的初步原理

其实AOF重写实现的原理很简单,比如我执行了一下几条指令的操作:

AOF重写样例

如果我们按照预期进行AOF持久化,我们需要保存四条指令,但是其实实际上我们只需要读取animals键对应的值,之后设置一条指令进行插入即可,即:

代码语言:txt复制
SADD animals "cat" "dog" "panda" "tiger" "lion"

其实保存这一条指令与保存四条指令的最终执行状态是一样的,就是用一条指令替换以前的多条指令,这就是AOF重写功能的实现,在Redis中主要由aof_rewrite函数实现,通过这个函数生成的新AOF文件只包含还原当前数据库状态必须的指令,因此新的AOF文件不会浪费任何硬盘空间

AOF重写功能的优化

一般的AOF重写程序aof_rewrite函数可以很好地完成创建新AOF文件的任务,但是如果仅仅通过这个命令进行AOF持久化,由于大量的写入操作,会导致调用这个线程的函数被长时间阻塞,而Redis服务器又实用单个线程来处理命令请求,所以如果调用aof_write函数会导致服务端无法处理客户端发来的其他命令请求

很明显,Redis不希望AOF重写造成服务器无法继续处理请求,所以Redis将AOF重写程序放到子进程里面执行,也就是AOF后台重写,在Redis中为BGREWRITEOF命令,这样做可以实现两个目的:

1、继续处理命令请求:子进程进行AOF期间,服务器进程(父进程)可以继续处理命令请求

2、保证数据安全性:子进程带有服务器进程的数据副本,使用子进程而不是线程,可以在避免使用锁的情况下,保证数据的安全性

但是这时又出现了一个新问题:如果服务器在子进程进行AOF重写过程中又有新的命令执行,那么又如何保证AOF文件的正确性呢?

为此Redis服务器设置了一个AOF重写缓冲区,在子进程执行AOF命令期间,如果Redis服务器又收到了新命令,那么它会将这个写命令同时发送到AOF缓冲区AOF重写缓冲区中,而当子进程完成了AOF重写工作后,它会向父进程发送信号,父进程收到信号后会执行一个信号处理函数,执行以下工作:

1)将AOF重写缓冲区中的所有内容写到新AOF文件中,这时新AOF文件所保存的数据库状态将与服务器当前的数据库状态保持一致

2)对新的AOF文件进行改名,原子地(atomic)覆盖现有的AOF文件,完成新旧两个AOF文件的切换

下表展示了一个示例AOF文件后台重写的执行过程:

时间

服务器进程(父进程)

子进程

T1

SET k1 v1

T2

SET k2 v2

T3

SET k3 v3

T4

创建子进程执行AOF文件重写

开始AOF文件重写

T5

SET k2 10086

执行重写操作

T6

SET k3 12345

执行重写操作

T7

执行命令SET k4 22222

完成AOF文件重写,向父进程发送信号

T8

接收到子进程发来的信号,将命令SET k2 10086、SET k3 12345、SET k4 22222追加到新AOF文件的末尾

T9

用新AOF文件覆盖旧AOF文件

这样通过BGREWRITEOF命令,Redis服务器就将原本一直阻塞服务器线程的时间,压缩为了只需要执行信号处理程序的时间,提高了Redis服务器处理命令的效率

至此,这就是AOF重写优化的全部内容了,希望对你有所帮助!!!

本文标签: Redis持久化策略AOF重写优化原理