Pre
我們一直說 Redis 是單線程的,這裏的我們默認指的都是Redis主要的工作線程,面向開發的。 實際上 Redis 內部實並不是只有一個主線程,它有很多個異步線程專門用來處理一些耗時的操作
del ------> unlink
刪除指令 del 會直接釋放對象的內存,大部分情況下,這個指令非常快,沒有明顯延遲。不過如果刪除的 key 是一個非常大的對象,舉個例子一個包含幾千萬元素的key,那麼刪除操作就會導致單線程卡頓。
Redis 爲了解決這個卡頓問題,在 4.0 版本引入了 unlink 指令,它能對刪除操作進行懶處理,丟給後臺線程來異步回收內存。
192.168.18.131:8001> set artisan vv
-> Redirected to slot [4009] located at 192.168.18.133:8006
OK
192.168.18.133:8006> UNLINK artisan
(integer) 1
192.168.18.133:8006> UNLINK artisan
(integer) 0
192.168.18.133:8006>
FLUSHDB/FLUSHALL --> FLUSHDB ASYNC/FLUSHALL ASYNC
Redis 提供了 flushdb 和 flushall 指令,用來清空數據庫,當數據量很大時,容易阻塞Redis。
Redis 4.0 同樣給這兩個指令也帶來了異步化,在指令後面增加 async 參數扔給後臺線程銷燬,不會阻塞當前線程。
192.168.18.133:8006> FLUSHDB ASYNC
OK
192.168.18.133:8006> FLUSHALL ASYNC
OK
192.168.18.133:8006>
異步隊列
主線程將對象的引用從「大樹」中摘除後,會將這個 key 的內存回收操作包裝成一個任務,塞進異步任務隊列,後臺線程會從這個異步隊列中取任務。
任務隊列被主線程和異步線程同時操作,所以必須是一個線程安全的隊列。
不是所有的 unlink 操作都會延後處理,如果對應 key 所佔用的內存很小,延後處理就沒有必要了,這時候 Redis 會將對應的 key 內存立即回收,跟 del 指令一樣。
AOF Sync
Redis 需要每秒一次(可配置)同步 AOF 日誌到磁盤,確保消息儘量不丟失,需要調用
sync 函數,這個操作會比較耗時,會導致主線程的效率下降,所以 Redis 也將這個操作移到異步線程來完成。
執行 AOF Sync 操作的線程是一個獨立的異步線程,和前面的懶惰刪除線程不是一個線程,同樣它也有一個屬於自己的任務隊列,隊列裏只用來存放 AOF Sync 任務
redis 4.0這次除了顯示增加unlink、flushdb async、flushall async命令之外,還增加了4個後臺刪除配置項,分別爲:
- slave-lazy-flush:slave接收完RDB文件後清空數據選項
- lazyfree-lazy-eviction:內存滿逐出選項
- lazyfree-lazy-expire:過期key刪除選項
- lazyfree-lazy-server-del:內部刪除選項,比如rename srckey destkey時,如果destkey存在需要先刪除destkey
以上4個選項默認爲同步刪除,可以通過config set [parameter] yes打開後臺刪除功能。