《Redis设计与实现》- AOF持久化
1. AOF持久化
Redis AOF 持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。
2. RDB持久化与AOF持久化的区别
-
RDB持久化
- RDB持久化通过保存数据中的键值对来记录数据库状态
- RDB文件是一个压缩的二进制文件
-
AOF持久化
- AOF 持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的
- AOF 文件是纯文本格式文件,所有写入AOF文件的命令都是以Redis请求协议格式保存的
3. AOF持久化的实现
AOF持久化功能的实现可以分为命令追加(append)、文件写入、文件同步(sync)三个步骤。
3.1 命令追加
当AOF持久化功能处于打开状态时,服务器在执行完一个写命令后,会以协议格式将被执行的写命令追加到服务器状态的 aof_buf缓存区的末尾。
3.2 AOF文件的写入和同步
文件的写入和同步:
为了提高文件的写入效率,在现代操作系统中,当用户调用 write 函数,将一些数据写入到文件的时候,操作系统通常会将写入数据暂时保存在一个内存缓冲区里面,等到缓冲区空间被填满,或者超过了指定的时限后,才真正地将缓冲区中的数据写入到磁盘里面。
这种做法虽然提高了效率,但也为写入数据带来了安全性问题,因为如果计算机发生停机,那么保存在内存缓冲区里面的写入数据将会丢失。
为此,系统提供了 fsync 和 fdatasync 两个同步函数,它们可以强制操作系统立刻将缓冲区中的数据写入到硬盘里边,从而确保写入数据的安全性。
Redis中通过配置 appendsync 选项的值来决定AOF文件写入和同步的行为。
appendsync 选项不同的取值产生的持久化行为以及对应的持久化效率和数据安全性如下表:
appendsync选项的值 | 持久化行为 | 效率 | 安全性 |
---|---|---|---|
always | 将 aof_buf 缓冲区中的所有内容写入并同步到AOF文件(保存到磁盘) | 最慢 | 最安全,即使故障停机,AOF持久化也只会丢失一个事件循环中所产生的命令数据 |
everysec | 将 aof_buf 缓冲区中的所有内容写入到AOF文件,如果上次同步的AOF文件的时间距离现在超过一秒钟,那么再次对AOF文件进行同步,并且这个同步操作是由一个子线程专门负责执行 | 足够快 | 故障停机,数据库也只丢失一秒钟的命令数据 |
no | 将 aof_buf 缓冲区中的所有内容写入AOF文件,但并不对AOF文件进行同步,何时同步由操作系统决定 | 最快 | 故障停机时,会丢失上次同步AOF文件之后所有写命令数据 |
4. AOF重写
为了解决AOF文件体积膨胀的问题,Redis提供了AOF文件重写功能。
AOF文件重写是通过读取服务器当前数据库状态来实现的,与现有的AOF文件没任何关系,不会对现有的AOF文件进行任何的读取、分析或者写入操作。
Redis 将AOF重写程序放到子进程中直行,防止服务器因AOF重写而无法处理请求。
Redis使用子进程处理AOF重写的好处:
- 子进程进行AOF重写期间,服务器进程可以继续处理命令请求
- 子进程带有服务器进程的数据副本,使用子进程而不是线程,可以在避免使用锁的情况下,保证数据的安全性
4.1 如何解决子进程AOF重写期间,服务器数据库状态与重写后的AOF文件数据库状态不一致的情况
为了解决数据不一致的问题,Redis服务器设置了一个AOF重写缓冲区,这个缓存区在服务器创建了子进程之后开始使用,当Redis服务器执行完一个写命令后,它会同时将这个写命令发送给AOF缓存区和AOF重写缓存区。
当子进程完成重写工作后,向父进程发送一个信号,父进程接收到信号后,调用信号处理函数(这个过程服务器进程是阻塞的,不能处理新命令请求):
- 将AOF 重写缓冲区中的所有内容写入新的AOF文件
- 原子地覆盖现有的AOF文件