「 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文件,就不會丟失了。
往期文章回顧: