redis AOF原理讲解
1.什么是AOF
它也是Redis持久化的重要手段之一,aof-》Append Only File,只追加文件,也就是每次处理完请求命令后都会将此命令追加到aof文件的末尾。而RDB是压缩成二进制等时机开子进程去干这件事,rdb是基于全量的追加,是开子线程去将数据先写入到一个临时文件中去,待持久化完成后,再用这个临时文件去替代之前的dump.rdb文件
优点:
- 持久化的速度快,因为每次都只是追加,rdb每次都全量持久化
- 数据更加的可靠,因为是每次修改了值就会进行一个保存。
缺点 - 灾难性恢复的时候过慢,因为aof每次都只追加原命令,导致aof文件过大,虽然后面会rewrite,但是相对于rdb也是慢的。
- 会对主进程对外提供请求的效率造成影响,接收请求、处理请求、写aof文件这三步是串行原子执行的。而非异步多线程执行的。Redis单线程!
2.AOF原理
AOF追加数据的时候并不会fork子进程,只有再进行重写的时候才会去fork子进程
就是每次都在aof文件后面追加命令。他与主进程收到请求、处理请求是串行化的,而非异步并行的。图示如下
所以aof的频率高的话绝逼会对Redis带来性能影响,因为每次都是刷盘操作。跟mysql一样了。Redis每次都是先将命令放到缓冲区,然后根据具体策略(每秒/每条指令/缓冲区满)进行刷盘操作。如果配置的always,那么就是典型阻塞,如果是sec,每秒的话,那么会开一个同步线程去每秒进行刷盘操作,对主线程影响稍小。
redis配置文件中对刷盘操作的控制
redis.conf具体参数讲解链接
appendfsync everysec
appendfsync alawys
appendfsync no
3.rewrite
为什么要进行rewite呢,因为aof是基于文件去进行命令的追加,那我项目如果运行了很久,那这个文件不是得非常大嘛。而且如果我只是反复的对一个key进行修改,那么大的数据都只是记录了那么一点数据变动。这是有问题的
4.4.0版本之前的rewrite
Redis4.0之前和Redis4.0的rewrite(重写)方式不一样,Redis4.0之前就是将aof文件中重复的命令给去掉。保留最新的命令。进而减少aof文件大小。比如
set k1 123
set k1 345
del k1
set k1 789
经过4.0版本之前的rewrite之后 会变成
set k1 789
5. 4.0版本之后的rewrite
4.0之前的做法效率很是低下,需要逐条命令对比。4.0开始的rewrite支持混合模式(也是就是rdb和aof一起用),直接将rdb持久化的方式来操作将二进制内容覆盖到aof文件中(rdb是二进制,所以很小),然后再有写入的话还是继续append追加到文件原始命令,等下次文件过大的时候再次rewrite(还是按照rdb持久化的方式将内容覆盖到aof中)。但是这种模式也是配置的,默认是开,也可以关闭。aof像是mysql中的binlog 或者说是undo log 都是记录逻辑变化 而rdb像是redo log 是一个物理记录。所以采用混合模式的话,重写的效率将大大提升。
5.1 rewite的触发条件
1.手动触发
客户端输入
bgrewriteaof 命令
2.自动触发
redis.conf 里面有两个配置
- auto-aof-rewrite-min-size
AOF文件最小重写大小,只有当AOF文件大小大于该值时候才可能重写,4.0默认配置64mb。
- auto-aof-rewrite-percentage
当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比,如100代表当前AOF文件是上次重写的两倍时候才重写。
3.触发满足条件
没有BGSAVE命令(RDB持久化)/AOF持久化在执行
没有BGREWRITEAOF在进行
前两点也就是说只允许同时fork()一个子进程出来干活。
6.rewrite 原理
- aof_rewrite_buf:rewrite(重写)缓冲区、aof_buf:写命令存放的缓冲区
开始bgrewriteaof的时候,判断当前有没有bgsave/bgrewriteaof在执行,若有,则不执行 - 主进程fork()出子进程,在执行fork()这个方法的时候是阻塞的,子进程创建完毕后就不阻塞了
- 主进程fork完子进程后,主进程能继续接收客户端的请求,所有写命令依然是写入AOF文件缓冲区并根据配置文件的策略同步到磁盘的。
- 因为fork的子进程仅仅共享主进程fork()时的内存,后期主进程在更改内存数据,子进程是不可见的。因此Redis采取重写缓冲区(aof_rewite_buf)保存fork之后的客户端请求。防止新AOF文件生成期间丢失主进程执行的新命令所生成的数据。所以此时客户端的写请求不仅仅写入原来的aof_buf缓冲区,还写入了重写缓冲区。这就是我为什么用深蓝色的框给他两框到一起的原因。
- 子进程通过内存快照的形式,开始生成新的aof文件。
新aof文件生成完后,子进程向主进程发信号。 - 主进程收到信号后,会把重写缓冲区(aof_rewite_buf)中的数据写入到新的AOF文件(主要是避免这部分数据丢失)
- 使用新的AOF文件覆盖旧的AOF文件,且标记AOF重写完成。
7.RDB-AOF混合持久化
1.优点
混合持久化结合了RDB持久化 和 AOF 持久化的优点,采取了rdb的文件小易于灾难恢复,同时结合AOF,增量的数据以AOF方式保存了,数据更少的丢失。
2.缺点
兼容性差,一旦开启了混合持久化,在4.0之前版本都不识别该aof文件,同时由于前部分是RDB格式,需要专业的工具来阅读,因为是二进制,所以阅读性较差。
3.原理
混合持久化也是通过bgrewriteaof完成的,所以基本流程和上述一样。不同的是当开启混合模式时,fork出的子进程先将共享的内存副本全量以RDB的方式写入aof。这样提高了速度也极大的缩小了aof文件(毕竟都是二进制)。写完还是通知主进程,然后再将重写缓冲区的内容以AOF方式写入到文件,然后替换旧的aof文件。也就是说这种模式下的aof文件发生rewrite后前半部分是rdb格式(REDIS开头的二进制数据),后半部分是正常的aof追加的命令(重写缓冲区里的)。
7.恢复机制
会优先看是否存在aof文件,若存在则先按照aof文件恢复,因为aof毕竟比rdb全。若aof不存在,则才会查找rdb是否存在。这是默认的机制。毕竟aof文件也rewrite成rdb二进制格式,文件小,易于回复。所以redis会优先采取aof。