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函数是一个实例,定期对自身资源和状态进行检查和调整。
文件事件和时间事件是合作关系,服务器会轮流处理,并且不会抢占。