与RDB持久化通过保存数据库中的键值对来记录数据库状态不同, AOF持久化是通过保存Redis服务器所执行的写命令
来记录数据库状态的。
AOF持久化的实现
AOF持久化功能的实现可以分为命令追加(append)
,文件写入
,文件同步(sync)
三个步骤
命令追加
当AOF持久化功能处于打开状态时, 服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾
:
struct redisServer {
// AOF缓冲区
sds aof_buf;
}
AOF文件的写入与同步
redis的服务器进程就是一个时间循环, 这个循环中的文件事件负责接收客户端的命令请求, 以及向客户端发送命令回复, 而时间事件负责执行像serverCron
函数这样需要定时运行的函数.
appendfsync选项
对于向aof文件写入内容的行文, 可以通过appendfsync选项
进行控制, 不同的值决定了不同的行为.
appendfsync选项的值 | flushAppendOnlyFile函数的行为 |
---|---|
always | 将aof_buf 缓冲区中的所有内容写入并同步到AOF文件 |
everysec(默认) | 将aof_buf 缓冲区中的所有内容写入到AOF文件, 如果上次同步AOF文件的时间距离现在超过一秒, 那么再次对AOF文件进行同步, 并且这个同步操作是由一个线程专门负责执行的 |
no | 将aof_buf缓冲区中的所有内容写入到AOF文件, 但并不对AOF文件进行同步, 何时同步由操作系统来决定 |
AOF持久化的效率和安全性
always
: 服务器在每个时间循环都要将aof_buf
缓冲区中的所有内容写入到AOF文件, 并且同步AOF文件, 所以always
效率是最慢的, 但是安全性是最好的.因为即使出现故障停机, AOF持久化也只会丢失一个事件循环中所产生的命令数据everysec
, 服务器在每个事件循环都要将aof_buf
缓冲区中的所有内容写入到AOF文件, 并且每隔一秒就要在线程中对AOF文件进行一次同步.everysec
模式足够快,就算出现故障停机, 数据库也只丢失一秒的命令数据。no
: 在每个事件循环都要讲aof_buf
缓冲区中的所有内容写入到AOF文件, 但是对于aof文件的同步则有系统确定.这种模式会在系统缓存中积累写入数据, 因此该种模式是三个模式中单词同步时间最长的。
重写
AOF通过记录写入命令记录数据库状态, 随着时间的推移, AOF文件将会越来越大.这是我们可以通过AOF
重写功能, 通过该功能, Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件, 新旧两个AOF文件所保存的数据库状态时相同, 但新AOF文件不会包含任何浪费空间的冗余命令。
限制
在实际中, 为了避免在执行命令时造成客户端输入缓冲区溢出, 重写程序在处理列表, 哈希表, 集合, 有序集合这四种可能会带有多个元素的键时, 会先检查键所包含的元素数量, 如果超过了REDIS_AOF_REWRITE_ITEMS_PER_CMD
常量值, 那么重写程序将使用多条命令来记录键的值, 而不是单单使用一条命令。
AOF后台重写
redis是一个单线程方式执行redis命令,但是aof_rewrite
函数是一个阻塞函数, 在执行aof_rewrite
的时候, 将导致redis无法处理客户端的请求, 因此redis将aof重写程序放到子进程里执行, 这样可以达到两个目的:
- 子进程进行AOF重写期间, 服务器进程可以继续处理命令请求
- 子进程带有服务器进程的数据副本, 使用子进程而不是线程, 可以避免使用锁的情况下, 保证数据的安全性。
AOF 重写实现方式
- AOF重写是通过读取数据库中的键值对来实现的, 程序无须对现有AOF文件进行任何读入, 分析或者写入操作.
面临的问题
使用子进程也有一个问题需要解决, 因为子进程在进行AOF重写期间, 服务器进程还需要继续处理命令请求, 而新的命令可能会对现有的数据库状态进行修改, 从而使得服务器当前的数据库状态和重写后的AOF文件所保存的数据库状态不一致。
解决重写后的AOF状态和数据库状态不一致的问题
Redis
服务器设置了一个AOF重写缓冲区, 这个缓冲区在服务器创建子进程之后开始用, 当redis服务器执行完一个写命令之后, 它会同时将这个写命令发送到AOF缓冲区和AOF重写缓冲区.
当子进程完成AOF重写工作之后, 它会向父进程发送一个信号, 父进程在接到高信号之后, 会调用一个信号处理函数, 并执行以下工作:
- 将AOF重写缓冲区中的所有内容写入到新AOF文件中, 这时新AOF文件所保存的数据库状态将和服务器当前的数据库状态一致
- 对新的AOF文件进行改名, 原子地覆盖现有的AOF文件, 完成新旧两个AOF文件的替换
这个信号处理函数完毕之后, 父进程就可以继续像往常一样接收命令请求了。
NOTE: 在父进程同步AOF重写缓冲区中的内容到AOF文件中的时候, 无法继续处理客户端发来的请求, 这时将会有短暂的阻塞。
这个就是BGREWRITEAOF
命令的实现原理
文章评论