redis靈魂拷問:聊一聊AOF日誌重寫

「 AOF日誌重寫到底會不會阻塞主線程?」redis

01

緩存

AOF介紹

redis的AOF日誌,是redis持久化的一種方式,它是一種write after log,即先執行命令後記錄日誌。這樣的好處是日誌不會記錄執行失敗的命令,同時記錄日誌不會阻塞當前命令執行。markdown

記錄AOF是在主線程中執行的,因此也會阻塞主線程。這個跟AOF的寫回策略有關,這個配置項參數叫appendfsync,在redis.conf文件中,默認值是everysec。下面是3種寫回策略的比較:數據結構

redis靈魂拷問:聊一聊AOF日誌重寫
這樣,咱們就須要在性能和可靠性之間作一些取捨了。app

當redis上執行的命令愈來愈多,AOF日誌文件會變得很大,這樣AOF文件追加命令會很慢,並且操做系統對文件大小也有必定的限制,再者若是使用AOF作主從同步或數據恢復的話,由於命令記錄太多會致使耗時很長。redis解決這個問題的手段就是AOF日誌重寫。ide

02

性能

AOF重寫介紹

在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條命令。

03

AOF重寫對性能的影響

在上小節的介紹中,若是AOF文件較上次重寫超過了100%,就要進行重寫。可是若是日誌特別大,AOF重寫後把日誌寫回磁盤也是一個很是耗時的操做,那麼AOF重寫是否會阻塞主線程呢?

AOF重寫並非在主線程中,而是redis會fork一個bgrewriteaof子進程,這樣就不會阻塞主線程執行了。

fork子進程的過程是要在主線程中執行的,這時候主線程須要拷貝內存頁表,這個頁表記錄了虛擬內存和物理內存的映射關係,若是內存很大,拷貝過程花費的時間就會很大,而這個拷貝過程當中主線程是阻塞的。

fork子進程完成後,主線程和bgrewriteaof子進程使用的是同一起內存空間,這時若是有新的寫請求到來,而且寫命令是已經存在的key,主線程會使用CopyOnWrite的方式,爲這個key申請新的內存空間,進行寫操做。若是這個key是一個bigkey,那也會耗時不少。

下面我畫了一個簡單的圖,主線程fork出bgrewriteaof子進程時,複製了一個頁表給子進程用,跟本身指向相同的內存空間。可是AOF重寫過程當中收到了foo這個key的寫命令,這時主線程須要拷貝一份數據到新的內存空間進行修改。

redis靈魂拷問:聊一聊AOF日誌重寫

在AOF重寫的過程當中,若是有新的寫命令到來了,會影響AOF重寫嗎?

固然不會,新的寫命令不只會記錄到AOF日誌的緩存區,還會記錄到重寫的新AOF日誌緩存區,這樣當AOF重寫結束後,把從新緩存區數據寫到新AOF文件,就不會丟失了。

往期文章回顧:

《redis靈魂拷問:聊一聊redis底層數據結構》

《redis靈魂拷問:怎樣搭建一個哨兵主從集羣》

相關文章
相關標籤/搜索