AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。
11.1 AOF持久化的实现
AOF持久化功能的实现可以分为命令追加、文件写入、文件同步三个步骤
11.1.1 命令追加
当AOF持久化功能打开时,服务器执行完一个写命令,会在服务器状态的aof_buf缓冲区的末尾添加被执行的写命令:
struct redisServer{ //AOF缓冲区 sds aof_buf; }
11.1.2 AOF文件的写入和同步
Redis的服务器进程就是一个事件循环,一个循环中会执行文件事件和时间事件。其中
文件事件:负责接收客户端的命令请求、向客户端发送回复命令
时间事件:执行定时运行的函数或周期性函数
AOF文件的写入和同步是分开的,写入是指写入硬盘缓存,同步是通过硬盘缓存机制刷新到文件。当Redis完成一个事件循环后,考虑到可能执行了写命令,导致aof_buf缓冲区更新了命令,Redis会执行flushAppendOnlyFile函数将缓冲区的内容写入及同步到AOF文件,具体的操作由appendfsync配置
-
- always:将aof_buff缓冲区的所有内容写入并同步到AOF文件
- everysec:将aof_buf缓冲区所有内容写入AOF文件,如果距离上次同步超过一秒,将再次同步,同步的操作由专门的线程执行
- no:将aof_buf缓冲区所有内容写入AOF文件,何时同步由操作系统决定
11.2 AOF文件的载入和数据还原
创建一个没有网络连接的伪客户端(Redis命令只能在客户端的上下文中执行,直接从AOF文件中读取命令不需要网络),读取AOF文件中的命令交与伪客户端执行。当数据量大时,写入比较耗时。
11.3 AOF重写
当Redis服务器运行时间越来越长,AOF文件中保存的命令越来越多,为了解决AOF文件体积膨胀的问题,Redis提供了AOF文件重写的功能,根据当前的数据库状态生成一个新的AOF文件(不是根据原AOF文件),简化执行步骤。
11.3.1 AOF文件重写的实现
读取当前数据库状态,只生成必要的插入语句,当处理列表、哈希表、集合、有序集合时,如果元素的个数超过了64个,则会生成多条插入语句,每条语句最多插入64个元素。
11.3.2 AOF后台重写
重写AOF文件时会造成当前执行的线程阻塞,为了不影响服务器处理请求,Redis生成一个子进程处理AOF文件的重写。
- 使用子进程,父进程依然可以处理请求
- 子进程会带有服务器进程的数据副本,使用子进程而不是线程,可以避免使用锁的情况下,保证数据的安全。
使用数据副本会带来数据不一致的问题,当子进程根据副本重写AOF文件时,父进程依然在处理请求。
Redis有一块内存称为AOF重写缓冲区。当子进程重写AOF文件时,父进程会将这段时间的写请求记录到AOF缓冲区和AOF重写缓冲区,当子进程重写完毕,父进程会将AOF重写缓冲区的内容写入到新的AOF文件末尾,并对新的AOF文件改名,原子的覆盖原有的AOF文件,完成新旧AOF文件的替换。父进程执行这段操作时,会被阻塞,不再处理请求。