AOF持久化 - 《Redis設計與實現》讀書筆記
AOF持久化:通過儲存Redis伺服器執行的寫命令
來記錄資料庫狀態
AOF持久化的實現
AOF持久化的步驟:
-
寫命令追加到伺服器狀態的aof_buf緩衝區
此步驟由feedAppendOnlyFile函式完成當AOF持久化功能處於開啟狀態時,伺服器在執行完一個命令之後,
會以協議格式將被執行的寫命令追加到伺服器狀態的aof_buf緩衝區的末尾 -
將aof_buf中的內容寫入到記憶體緩衝區aof檔案
-
同步記憶體緩衝區的aof檔案資料到磁碟的aof檔案
步驟2和步驟3由flushAppendOnlyFile函式完成伺服器配置
appendfsync選項
的值直接決定aof持久化功能的效率和安全性(flushAppendOnlyFile函式的行為)
appendfsync選項的值 | flushAppendOnlyFile函式的行為 |
---|---|
always | 將aof_buf緩衝區中的所有內容寫入並同步 到AOF檔案效率最慢,安全性最強(只會丟失一個事件迴圈中所產生的命令資料) |
everysec(預設值) | 將aof_buf緩衝區中的所有內容寫入 到AOF檔案,如果上次同步AOF檔案的時間距離現在超過一秒鐘,那麼啟動一個執行緒開始對AOF檔案進行同步 效率足夠快,安全性較好(只會丟失一秒的命令資料) |
no | 將aof_buf緩衝區中的所有內容寫入 到AOF檔案,由作業系統決定對AOF檔案何時進行同步 寫入速度最快,同步時間最長,安全性較差(丟失上次同步AOF檔案之後的所有寫命令資料) |
⚠️注意⚠️:
為了提高檔案的寫入和效率,在作業系統中,當用戶呼叫write函式,
將一些資料寫入到檔案的時候,作業系統通常會將寫入資料暫時儲存在一個記憶體緩衝區裡面
,
等到緩衝區的空間被填滿 或者 超過了指定的時限之後,才真正地將緩衝區中的資料寫入到磁盤裡面由此導致資料儲存在記憶體緩衝區的資料有可能丟失,
為此,作業系統提供了fsync和fdatasync兩個同步函式,
強制讓作業系統立即將緩衝區的資料寫入到磁盤裡面,從而保證資料的安全性
在Linux作業系統中,Redis用fdatasync作為強制同步函式
其餘作業系統中,Redis用fsync作為強制同步函式
AOF檔案的載入
伺服器只要讀入並重新執行一遍AOF檔案裡面儲存的寫命令,就可以還原伺服器關閉之前的資料庫狀態
讀取AOF檔案並還原資料庫狀態的步驟:
-
建立一個不帶網路連線的偽客戶端
Redis的命令只能在客戶端上下文中執行 -
從AOF檔案中分析並讀取出一條寫命令
-
使用偽客戶端執行被讀出的寫命令
-
一直執行步驟2和步驟3,直到AOF檔案中給所有的寫命令都被處理完畢為止
AOF重寫
AOF檔案重寫
建立一個新的資料庫狀態相同的AOF檔案替代現有的AOF檔案,去掉浪費空間的冗餘命令,從而新的AOF檔案的體積 <= 舊AOF檔案體積
實現原因
: 為了解決隨著伺服器執行時間越長,AOF檔案體積膨脹的問題,
實現原理
: 從資料庫中讀取鍵現在的值,然後用一條命令去記錄鍵值對,代替之前記錄這個鍵值對的多條命令
⚠️注意⚠️:
- 為了避免在執行命令時造成客戶端輸入緩衝區溢位,重寫程式在處理列表、雜湊表、集合、有序集合這四種可能會帶有多個元素的鍵時,會先檢查鍵所包含的元素數量,如果
鍵所包含的元素數量超過了src/server.h/AOF_REWRITE_ITEMS_PER_CMD常量的值
,Redis 6.2版本的值為64,那麼重寫程式將使用多條命令來記錄鍵的值
,而不單單使用一條命令
AOF後臺重寫
Redis伺服器使用單個執行緒處理命令請求,而AOF檔案重寫是放線上程中執行,
為了在重寫AOF檔案期間,伺服器可以繼續處理命令請求,Redis將AOF重寫程式放到子程序裡執行
⚠️注意⚠️:
由於Redis將AOF重寫程式放到子程序裡執行,由此可能導致資料庫狀態不一致的問題,
所以伺服器狀態添加了一個server.aof_rewrite_buf_blocks(AOF重寫緩衝區)
,
這個緩衝區儲存伺服器建立子程序之後對資料庫狀態修改的寫命令
AOF後臺重寫的步驟:
- 伺服器父程序建立子程序,執行AOF檔案重寫
子程序開始執行AOF檔案重寫操作 - 伺服器父程序
繼續處理
客戶端發來的命令
子程序執行AOF檔案重寫... - 伺服器父程序將執行後的寫命令追加到AOF緩衝區
子程序執行AOF檔案重寫... - 伺服器父程序
將執行後的寫命令追加到AOF重寫緩衝區
子程序執行AOF檔案重寫... - 子程序完成AOF檔案重寫,向伺服器父程序傳送訊號
伺服器父程序接到訊號,呼叫訊號處理函式 - 伺服器父程序
將AOF重寫緩衝區的內容追加到AOF檔案中
這時新AOF檔案所儲存的資料庫狀態和伺服器當前的資料庫狀態保持一致 對新的AOF檔案進行改名
,原子地覆蓋現有的AOF檔案,完成新舊兩個AOF檔案的替換
⚠️注意⚠️:
在整個AOF後臺重寫過程中過,只有第5~7步會讀伺服器父程序造成阻塞
,這將AOF重寫對伺服器效能造成的影響降到了最低
原始碼閱讀
- AOF持久化-第一個步驟-命令追加:src/aof.c/feedAppendOnlyFile
- AOF持久化-第二、三個步驟-aof檔案的寫入與同步:src/aof.c/flushAppendOnlyFile
- AOF檔案重寫:src/aof.c/rewriteAppendOnlyFile
- AOF檔案後臺重寫:src/aof.c/rewriteAppendOnlyFileBackground