“ AOF日志重写到底会不会阻塞主线程?”redis
—缓存
redis的AOF日志,是redis持久化的一种方式,它是一种write after log,即先执行命令后记录日志。这样的好处是日志不会记录执行失败的命令,同时记录日志不会阻塞当前命令执行。markdown
记录AOF是在主线程中执行的,因此也会阻塞主线程。这个跟AOF的写回策略有关,这个配置项参数叫appendfsync,在redis.conf文件中,默认值是everysec。下面是3种写回策略的比较:数据结构
这样,咱们就须要在性能和可靠性之间作一些取舍了。app
当redis上执行的命令愈来愈多,AOF日志文件会变得很大,这样AOF文件追加命令会很慢,并且操做系统对文件大小也有必定的限制,再者若是使用AOF作主从同步或数据恢复的话,由于命令记录太多会致使耗时很长。redis解决这个问题的手段就是AOF日志重写。ide
—性能
在redis.conf文件中,有下面2个参数来控制AOF重写:操作系统
auto-aof-rewrite-percentage 100 #AOF文件大小较上次重写超过100%时进行重写 auto-aof-rewrite-min-size 64mb #aof文件大小超过64m时重写
下面咱们执行6条命令:线程
192.168.59.146:6379> set name jinjnzhu OK 192.168.59.146:6379> set password 123456 OK 192.168.59.146:6379> set name jinjunzhu1 OK 192.168.59.146:6379> set password 1234567 OK 192.168.59.146:6379> set name jinjunzhu2 OK 192.168.59.146:6379> set password 12345678 OK
以后咱们查看name和password的值:日志
192.168.59.146:6379> get name "jinjunzhu2" 192.168.59.146:6379> get password "12345678"
这2个key的值被赋予了最新的一次赋值,虽然咱们执行了6条命令,可是AOF重写后日志文件就剩了最后2条命令。
—
在上小节的介绍中,若是AOF文件较上次重写超过了100%,就要进行重写。可是若是日志特别大,AOF重写后把日志写回磁盘也是一个很是耗时的操做,那么AOF重写是否会阻塞主线程呢?
AOF重写并非在主线程中,而是redis会fork一个bgrewriteaof子进程,这样就不会阻塞主线程执行了。
fork子进程的过程是要在主线程中执行的,这时候主线程须要拷贝内存页表,这个页表记录了虚拟内存和物理内存的映射关系,若是内存很大,拷贝过程花费的时间就会很大,而这个拷贝过程当中主线程是阻塞的。
fork子进程完成后,主线程和bgrewriteaof子进程使用的是同一起内存空间,这时若是有新的写请求到来,而且写命令是已经存在的key,主线程会使用CopyOnWrite的方式,为这个key申请新的内存空间,进行写操做。若是这个key是一个bigkey,那也会耗时不少。
下面我画了一个简单的图,主线程fork出bgrewriteaof子进程时,复制了一个页表给子进程用,跟本身指向相同的内存空间。可是AOF重写过程当中收到了foo这个key的写命令,这时主线程须要拷贝一份数据到新的内存空间进行修改。
在AOF重写的过程当中,若是有新的写命令到来了,会影响AOF重写吗?
固然不会,新的写命令不只会记录到AOF日志的缓存区,还会记录到重写的新AOF日志缓存区,这样当AOF重写结束后,把从新缓存区数据写到新AOF文件,就不会丢失了。
往期文章回顾: