1. 程式人生 > 其它 >AOF持久化 - 《Redis設計與實現》讀書筆記

AOF持久化 - 《Redis設計與實現》讀書筆記

AOF持久化:通過儲存Redis伺服器執行的寫命令來記錄資料庫狀態

AOF持久化的實現

AOF持久化的步驟:

  1. 寫命令追加到伺服器狀態的aof_buf緩衝區
    此步驟由feedAppendOnlyFile函式完成

    當AOF持久化功能處於開啟狀態時,伺服器在執行完一個命令之後,
    會以協議格式將被執行的寫命令追加到伺服器狀態的aof_buf緩衝區的末尾

  2. 將aof_buf中的內容寫入到記憶體緩衝區aof檔案

  3. 同步記憶體緩衝區的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檔案並還原資料庫狀態的步驟:

  1. 建立一個不帶網路連線的偽客戶端
    Redis的命令只能在客戶端上下文中執行

  2. 從AOF檔案中分析並讀取出一條寫命令

  3. 使用偽客戶端執行被讀出的寫命令

  4. 一直執行步驟2和步驟3,直到AOF檔案中給所有的寫命令都被處理完畢為止

AOF重寫

AOF檔案重寫

建立一個新的資料庫狀態相同的AOF檔案替代現有的AOF檔案,去掉浪費空間的冗餘命令,從而新的AOF檔案的體積 <= 舊AOF檔案體積

實現原因: 為了解決隨著伺服器執行時間越長,AOF檔案體積膨脹的問題,

實現原理: 從資料庫中讀取鍵現在的值,然後用一條命令去記錄鍵值對,代替之前記錄這個鍵值對的多條命令

⚠️注意⚠️:

  1. 為了避免在執行命令時造成客戶端輸入緩衝區溢位,重寫程式在處理列表、雜湊表、集合、有序集合這四種可能會帶有多個元素的鍵時,會先檢查鍵所包含的元素數量,如果鍵所包含的元素數量超過了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後臺重寫的步驟:

  1. 伺服器父程序建立子程序,執行AOF檔案重寫
    子程序開始執行AOF檔案重寫操作
  2. 伺服器父程序繼續處理客戶端發來的命令
    子程序執行AOF檔案重寫...
  3. 伺服器父程序將執行後的寫命令追加到AOF緩衝區
    子程序執行AOF檔案重寫...
  4. 伺服器父程序將執行後的寫命令追加到AOF重寫緩衝區
    子程序執行AOF檔案重寫...
  5. 子程序完成AOF檔案重寫,向伺服器父程序傳送訊號
    伺服器父程序接到訊號,呼叫訊號處理函式
  6. 伺服器父程序將AOF重寫緩衝區的內容追加到AOF檔案中
    這時新AOF檔案所儲存的資料庫狀態和伺服器當前的資料庫狀態保持一致
  7. 對新的AOF檔案進行改名,原子地覆蓋現有的AOF檔案,完成新舊兩個AOF檔案的替換

⚠️注意⚠️:
在整個AOF後臺重寫過程中過,只有第5~7步會讀伺服器父程序造成阻塞,這將AOF重寫對伺服器效能造成的影響降到了最低

原始碼閱讀

  1. AOF持久化-第一個步驟-命令追加:src/aof.c/feedAppendOnlyFile
  2. AOF持久化-第二、三個步驟-aof檔案的寫入與同步:src/aof.c/flushAppendOnlyFile
  3. AOF檔案重寫:src/aof.c/rewriteAppendOnlyFile
  4. AOF檔案後臺重寫:src/aof.c/rewriteAppendOnlyFileBackground
隻言片語任我說,提筆句句無需忖。落筆不知寄何人,唯有邀友共斟酌。