这是我参与「第五届青训营 」伴学笔记创作活动的第 17 天
四、AOF持久化
AOF=append only file
AOF的保存就是简单的讲命令协议直接用文本的方式储存
AOF只会保存修改的命令(写和修改),不会保存读命令
1、AOF持久化的实现
AOF持久化实现有三步,分别为命令追加,文件写入,文件同步
命令追加:当执行一条写入或者修改的命令时,会把当前内容追加到redisServer的aof_buf缓存区
文件写入:服务器的进程是一个循环进程,当一轮循环结束的时候会调用flushAppendOnlyFile函数,这个函数会将aof_buf缓存区的内容写入到AOF文件里面。
flushAppendOnlyFile有三个参数
always:将aof_buf的数据全部写入并同步到AOF
everysec:把aof_buf的数据写入到AOF文件,如果上次同步的时间超过1s,则进行同步,否则不同步。
no:讲aof_buf的数据写入到AOF文件,不进行主动同步,同步交给操作系统
这里解释一下文件的写入和同步到底有什么区别
现代操作系统当调用write函数的时候,将一些数据写入到文件的时候,操作系统会把数据暂时保存到一个内存的缓存区里面,等到缓存区里面的数据满了或者长时间没进行写入操作才会将数据写入到磁盘上。调用write函数为写入,操作系统把文件写入到磁盘为同步。
这么做提高了数据写入的效率,但是当服务器宕机会造成数据的遗失,对于一些普通程序来说可能无伤大雅,但是对于Redis这种内存数据库来说,数据的丢失其实是不可接受的。
所以才会有always和everysec策略,当选择这两个策略的时候,redis就会直接执行同步操作,也就是直接把数据写入到磁盘。而不是交给操作系统来处理。
AOF的效率和安全性
always:当服务器宕机,数据库只会丢失一个事件循环(loop)产生的数据
everysec:当服务器宕机,数据库会丢失1s内产生的数据
no:这种情况下,因为无需同步,所以写入效率高,但是因为同步交给了操作系统,所以丢失的数据可能会很多
2、AOF文件的载入与数据还原
1、创建一个伪客户端,因为redis的命令只能在客户端中执行,但是在伪客户端中,不会执行网络传输过来的命令,而是读取AOF文件之中的命令。
2、从AOF中读取一条写命令
3、执行写命令
4、执行2.3直到AOF文件所有命令被处理完毕
3、AOF重写
AOF的重写主要是因为如果一直保存写命令,各种修改命令会无限的追加,导致文件无限膨胀。
AOF重写就是之前在RDB里面提到的REWRITEBGSAVE命令。值得注意的是,AOF命令由Redis服务器自动执行,只有重写可以由我们手动执行。
AOF的重写不是读取现有AOF文件然后进行筛选,这样效率极低
而是读取Redis数据库,通过数据库里的各个key对应的value来生成写的指令
如果value的数量超过默认(65)大小,会被拆成多个命令来执行
AOF重写会阻塞线程,影响当前的业务运行,所以需要子进程去执行命令
AOF重写还有一个要注意的事情,就是当执行重写期间有新的数据被写入,这些新的数据就会被写入到重写缓存区(不是aof_buf),当重写数据库数据完成,就会去读取重写缓冲区的数据写入到aof文件。
然后新的AOF文件替换旧的AOF文件,如此一来就可以保证重写过程中的安全性。
整个过程中,当子进程重写完毕当前数据库的数据以后,会发送信号给父进程,父进程会将重写缓冲区的数据写入到新的AOF文件以及新旧替换。只有这个过程中是由父进程执行(也就是阻塞其他操作)