与rdb持久化通过保存数据库中的键值对来记录数据库状态不同aof持久化是通过保存服务器所执行的写命令来保记录数据库
被写入aof文件的所有命令都是以redis的命令请求协议格式保存的,因为Redis的命令请求协议是纯文本格式,所以我们可以直接打开一个aof文件观察里面的内容。
A of持久化功能的实现可以分为命令追加(appen),文件写入,文件同步(sync) 3个步骤。
文件的写入和同步
为了提高文件的写入效率,在现代操作系统中,当用户调用write函数将一些数据写入到文件的时候,操作系统通常会将写入数据暂时保存在一个内存缓冲区里面,等到缓冲冲区的空间被填满或者超过了指定的时限之后,才真正的将缓冲区中的数据写入到磁盘里面。
这种做法虽然提高了效率,但也为写入数据带来了安全问题。因为如果计算机发生停机,那么保存在内存缓冲区里的写入数据将会丢失。
为此,系统提供了fsync和fdatasync 2个同步函数,他们可以强制让操作系统立刻将缓冲区中的数据写入到硬盘里面,从而确保写入数据的安全性。
Aof持久化的效率和安全性
服务器配置appendfsync选项的值直接决定aof持久化功能的效率和安全性。
当appendfsync的值为always时,服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到aof文件,并且同步aof文件。所以always的效率是选项三个值当中最慢的。但从安全性来说,Always也是最安全的,因为即使出现故障停机,Aof持久化也只会丢失一个事件循环中所有产生的命令数据。
当appendfsync的值为evenySEC时,服务器在每个事件循环中都要将aof_buf缓冲区中的所有内容写入到aof文件,并且每隔一秒就要在子线程中对aof文件进行一次同步。从效率上来讲,EvenySEC模式足够快,并且就算出现故障停机,数据库也只会丢失一个秒钟的命令数据。
当appendfsync的值为no时,服务器在每个事件循环中都要将aof_buf缓冲区中的所有内容写入到aof文件,至于何时对aof文件进行同步,则由操作系统控制。
因为aof文件里包含了重建数据库状态所需的所有写命令,所以服务器只要读入并重新写入一遍aof文件,里面保存了写命令,就可以还原服务器关闭之前的数据库状态。
redis读取aof文件并还原数据库状态的详细步骤如下。
bgrewriteaof
因为aof持久化是通过保存被执行的写命令来记录数据库的状态,所以随着服务器运行时间的流逝,Aof文件的内容会越来越多,文件的体积也会越来越大。为了解决aof文件体积膨胀的问题。Redis提供了aof文件重写功能(rewrite)。通过该功能,Redis服务器可以创建一个新的aof文件来替代现有的aof文件,新旧两个aof文件所保持的数据库状态相同。
11.3.1 aof文件重写的实现。
Aof文件重写功能是通过读取服务器当前的数据库状态来实现。首先从数据库中读取建现在的值,然后用一条命令去记录键值对代替之前记录这个键值对的多条命令。这就是aof重写功能的实现原理。
注意,在实际中,为了避免在执行命令时造成客户端输入缓冲区溢出,重写程序,在处理列表、哈希表、集合、有序集合这四种可能会带有多个元素的键时,会先检查键所包含的元素数量。如果元素的数量超过某个阀值(64mb),那么重写程序将会用多条命令来记录键的值,而不单单使用一条命令。
11.3.1 aof后台重写
Redis决定将aof重写程序放到子进程里执行
问题:因为子进程在进行a of重写期间,服务器进程还需要继续处理命令请求,而新的命令可能会对现有的数据库状态进行修改,从而使得服务器当前的数据库状态和重写后的a of文件所保持的数据状态不一致。
解决方案: