AOF持久化

除了RDB持久化之外,redis还提供了AOF(append only file)持久化功能。AOF持久化是通过redis服务器执行命令来记录数据库状态。如:

SET msg "hello"

就是将服务器执行的SET命令保存到AOF文件中,AOF是纯文本文件。AOF持久化的实现可以分为命令追加、文件写入、文件同步三个步骤。

文件追加

struct redisServer{
    sds aof_buf;//AOF缓冲区
} 

当服务端执行完命令后将内容放入缓冲区

写入与同步

redis服务进程就是事件循环,循环中的文件事件负责接收客户端的命令请求,以及回复。处理一个事件之前会调用flushAppendOnlyFile函数,考虑是否将缓冲区内容写入AOF文件。

文件的写入与同步:操作系统通常会将写入数据暂时保存在一个内存缓冲区里,等到缓冲区塞满或过时才写入磁盘,此举存在安全问题,容易断电丢失数据,可以根据操作系统提供函数强制同步。

文件载入与还原

AOF文件包含重建数据库的所有写命令,只要读入并重新执行即可还原状态。详细步骤如下:

  • 1)创建一个不带网络连接的伪客户端来执行AOF文件保存的写命令
  • 2)从AOF分析并读取一条命令
  • 3)伪客户端执行命令
  • 4)执行步骤2和3知道文件读取完成

AOF重写

将每个命令保存到AOF文件会存在冗余,为了节省空间。redis创建一个新的AOF文件来替代现有的AOF文件。

新的AOF文件依靠读取现有redis数据库状态来实现,即多次操作化简为单次。如:

rpush list "c"

rpush list "d" "e"

lpop list "c"

lpop list "d"
###################转换为
rpush "e"

实际情况下为了避免缓冲区溢出,也会考虑使用多条命令来记录值。

rpush item1 ... item64
rpush item65 ... item128

AOF重写涉及到大量写入操作会造成阻塞,所以重写程序放到子进程当中。子进程也存在一个问题,由于服务器在重写期间,服务器进程也在修改,导致新AOF文件与原始AOF文件不一致。为了解决这个问题,redis服务器设置了一个AOF重写缓冲区,当重写命令执行时,新追加的命令会同时追加到新旧AOF。

事件

redis服务器是一个事件驱动程序,服务器处理两类事件:

  • 文件事件:redis服务器通过socket与其他客户端、服务器连接,而文件事件就是操作socket的抽象,就是监听并处理这些传输数据。
  • 时间事件:redis服务器内部的一些操作,如RDB文件需要定时操作。

文件事件

文件事件是基于Reactor模式开发的网络事件处理器。使用IO多路复用来同时监听多个socket并关联不同的事件处理器。被监听的socket执行应答、读取、写入和关闭等操作,对应的文件事件就会产生。

文件事件有4个组成部份:socket、IO多路复用程序、文件事件分派器和事件处理器。

文件事件可能并发出现,IO多路复用程序会将事件的socket放入一个队列,以有序、同步、每次一个socket向事件分派器传送套接字。

redis的IO多路复用程序是通过包装操作系统的select、epoll、evport等多路复用函数库来实现的。

redis包括多个文件事件的处理器,如:

  • 连接应答处理器:accept操作
  • 请求命令处理器:关联命令操作
  • 命令回复处理器:回复客户端命令

时间事件

时间事件包括两类:定时事件和周期性事件。

一个时间事件包括三个属性

  • id 时间事件全局标识号
  • when 毫秒时间戳
  • timeProc 时间事件处理器

服务器将所有时间事件存放在无序链表中,执行时间事件处理器就遍历整个链表,并调用相应事件处理器。

serverCron函数是一个实例,定期对自身资源和状态进行检查和调整。

文件事件和时间事件是合作关系,服务器会轮流处理,并且不会抢占。