这里先要了解redis的执行机制:redis主进程本身是以事件循环的形式运行,主要分为处理写指令的文件事件,和处理定时任务的时间事件。
在处理写操作时,文件事件会将命令追加到aof缓冲区,由时间事件执行serverCron函数,调用flushAppendOnly函数进行文件的写入和同步。
这里涉及write和save两个函数:
- write: 将命令写入到AOF缓冲区中
- save:调用fsync或fdatasync函数将AOF缓冲区中内容写到磁盘
三种同步策略(即内存中AOF文件什么时候写入磁盘):
appendfsync no // 不保存 (write和save命令都由主进程完成)
appendfsync everysec // 每秒钟保存(write由主进程完成,save由子进程完成)
appendfsync always // 每次执行命令都保存(write和save都由主进程执行)
AOF_FSYNC_NO:
每次flushAppendOnlyFile函数调用时都执行一次write方法,但不执行save方法。
在这种策略下只有三种情况会执行save方法:
- redis服务被关闭
- aof功能被关闭
- 系统的缓存被写满,或是定期保存操作被执行
这三种情况的save都是由主进程完成,因此会造成主进程的阻塞,如果长时间没有执行save命令,会导致缓冲区内容过多,阻塞时间变得很长。
AOF_FSYNC_EVERYSEC:
每隔一秒钟执行一次save,在这种策略下,save操作由fork出的子进程调用,因此磁盘IO并不会阻塞主进程。根据Redis的状态,每当flushAppendOnlyFile被调用时,write和save的命令执行又分为几种情况:

由上图可以发现,在此策略下,如果情况1下发生宕机,最多只是损失2秒钟内的数据,如果是情况2下宕机,因为很久不执行save命令,有大量内容在缓冲区堆积,就可能损失超过2秒的数据。
AOF_FSYNC_ALWAYS:
每次执行完一个命令后,都会执行write和save操作,都由主进程直接执行,导致主进程阻塞
三种策略的比较
AOF_FSYNC_NO:在save不执行时的效率会很高,但是因为大量内容放在缓存中,在定时执行save的时候可能导致长时间的阻塞,并且如果在save执行前redis宕机,则缓冲区中的数据全部丢失,因此不适用于数据安全性要求严格的场景
AOF_FSYNC_EVERYSEC:这个策略是redis的默认策略,是在安全性和性能当中比较折中的一个策略。
AOF_FSYNC_ALWAYS: 此策略是安全性最高的策略,能够保证每一条命令都被持久化保存下来,至多丢失最后一条。但是主进程每一次都要执行write,save操作,对于性能影响很大
网友评论