为了避免Redis服务器宕机之后,内存中的数据全部丢失,所以Redis实现了数据的持久化,可以恢复Redis的缓存数据,保证数据的完整。
Redis共有两种持久化技术,分别为AOF日志和RDB快照,默认开启RDB快照。
AOF日志
下图为该章节的整体概览
AOF (Append Only File)
- 执行写命令到内存
- 记录命令到日志
写后日志,记录Redis收到的每一条写命令(记录读命令无意义),以文本形式保存
比如命令:set name libowei
下图展示AOF文件存储格式
写后日志的好处:
-
避免额外的检查开销
先写日志 --> 执行命令 如果语法有错误,恢复数据的时候,会出错
命令 --> 语法检查 --> 执行命令 --> 写入日志,这样不需要额外的检查开销,保证命令都是正确的且可执行的 -
不会阻塞当前写操作命令的执行
风险:- 执行命令 --> 宕机 --> 还没写日志
- 写日志到磁盘(I/O压力大) --> 阻塞下一个命令
解决方法:写回策略
三种写回策略
AOF配置项 appendfsync
- Always,同步写回
- Everysec,每秒写回
折中方案,Always可能阻塞主进程,影响性能;No不能保证数据完整性
宕机时会丢失1秒内数据 - No,操作系统决定
控制的时间段是:内核缓冲区的数据什么时候写入到硬盘,什么时候调用fsync()函数,将数据同步到硬盘
AOF重写机制
如果AOF文件越写越大,不加节制的话,等到恢复数据的时候就会很慢,所以需要使用AOF重写机制,把那些对新键值对更新没有影响历史命令删掉,进行压缩。
重写过程:
创建新的AOF文件,读取数据库的所有键值对,将每一个键值对用一条命令记录到AOF文件
记录完毕后,新的替换旧的文件
为什么创建新的AOF文件,在原本上改不好吗?
如果重写过程中失败了,那原有的AOF文件也受到影响,无法正确恢复
为了不阻塞主线程,重写是通过fork出子进程bgwriteaof来完成
选择子进程而不是线程:
多线程之间共享内存,如果有一个线程要更改共享内存数据的时候,需要加锁来保证数据的正确性,开销大;
父子进程要修改共享内存的时候,会触发“写时复制”,获得独立数据副本
但也会出现问题:重写的时候,新AOF文件记录了kv1,但是主线程又更改了kv1,那数据就不一致了
解决:设置AOF重写缓冲区,在重写期间,执行命令 --> 写入AOF缓冲区 + AOF重写缓冲区
下图展示了大致流程,并且标注了可能阻塞的时机