Redis 源碼簡潔剖析 15 - AOF

AOF 是什麼

Append Only File,通過保存 Redis 服務器所執行的命令來記錄數據庫狀態。

AOF 持久化的實現

命令追加

服務器在執行完一個寫命令後,會以協議格式將被執行的寫命令追加到服務器狀態的 aof_buf 緩衝區的末尾:

struct redisServer {
    ……
    // AOF 緩衝區
    sds aof_buf;
    ……
}

AOF 文件的寫入和同步

AOF 文件的載入和數據還原

流程:

AOF 重寫

爲什麼需要重寫

AOF 持久化是通過保存被執行的寫命令來記錄數據庫狀態的,隨着服務器運行時間的流逝,AOF 文件的內容會越來越多,文件體積越來越大。如果客戶端執行了下面的命令:

127.0.0.1:6379> set name yano
OK
127.0.0.1:6379> set name yano2
OK
127.0.0.1:6379> set name yano3
OK

那麼 AOF 文件就需要保存 3 條命令,不僅使保存的 AOF 文件體積變大,還使得 Redis 啓動時載入數據變慢。

什麼是重寫

AOF 文件重寫(rewrite),創建新的 AOF 文件替代現有的 AOF 文件,新舊兩個 AOF 文件所保存的數據庫狀態相同,但新 AOF 文件不會包含任何浪費空間的冗餘命令,體積更小。

如何重寫

不是讀取和分析現有的 AOF 文件內容,而是直接從數據庫讀取值組成相應的命令 AOF 文件。

AOF 後臺重寫

爲什麼需要後臺重寫

重寫函數 aof_rewrite 會進行大量的寫入操作,執行這個函數的線程會被長時間阻塞,但是 Redis 服務器使用單個線程來處理命令請求,如果直接在主線程直接更新,在重寫期間,服務器將無法處理客戶端發來的命令請求。所以將 AOF 重寫程序放到子進程中執行。

帶來的問題

子進程在進行 AOF 重寫期間,服務器進程還需要繼續處理命令請求,新的命令可能對現有的數據庫狀態進行修改,導致服務器當前數據庫狀態和重寫後的 AOF 文件保存的數據狀態不一致。

AOF 重寫緩衝區

爲了解決這種數據不一致的問題,Redis 設置了一個 AOF 重寫緩衝區,在服務器創建子進程之後開始使用,當 Redis 服務器執行完一個寫命令後,同時將這個寫命令發送給 AOF 緩衝區AOF 重寫緩衝區

當子進程完成 AOF 重寫工作後,它會向父進程發送一個信號,父進程在收到這個信號後,會調用一個信號處理函數:

  1. 將 AOF 重寫緩衝區的所有內容寫入新的 AOF 文件,這樣新 AOF 文件所保存的數據庫狀態就與服務器當前的數據庫狀態一致;
  2. 對新 AOF 文件改名,原子覆蓋現有的 AOF 文件,完成新舊 AOF 文件的替換。

下圖左邊是正常流程,右邊是 AOF 重寫期間的流程:

注意

在實際中,爲了避免在執行命令時造成客戶端輸入緩衝區的溢出,重寫程序在處理列表、哈希表、集合、有序集合可能帶有多個元素的鍵時,會先檢查鍵所包含的元素數量,如果元素數量超過了一個常量閾值,重寫程序會使用多條命令來記錄鍵的值。

實際例子

配置 redis.conf 文件,使用 AOF:

appendonly yes
appendfsync always
appendfilename "appendonly.aof"
dir ./

啓動 Redis server:

src/redis-server redis.conf&

啓動 Redis client:

src/redis-cli

設置 key:

127.0.0.1:6379> set name yano
OK
127.0.0.1:6379> set name yano2
OK
127.0.0.1:6379> set name yano3
OK

查看 appendonly.aof 文件:

➜  redis-6.2.6 cat appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$4
name
$4
yano
*3
$3
set
$4
name
$5
yano2
*3
$3
set
$4
name
$5
yano3

參考鏈接

Redis 源碼簡潔剖析系列

最簡潔的 Redis 源碼剖析系列文章

Java 編程思想-最全思維導圖-GitHub 下載鏈接,需要的小夥伴可以自取~

原創不易,希望大家轉載時請先聯繫我,並標註原文鏈接。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章