Redis 設計與實現 (三)--持久化

K戰神發表於2018-01-27

RDB 持久化

 一、生成RDB

  cmd:SAVE  --阻塞程式,執行完,才能有效接收客戶端命令。

  cmd:  BGSAVE  --非阻塞,開啟子程式儲存。

          客戶端如果傳送SAVE和BGSAVE命令直接拒絕。

          BGWRITEAOF命令再BGSAVE執行完才能執行。  

 二、載入RDB

  伺服器啟動時自動執行,檢測到RDB檔案就會自動載入。

  如果開啟AOF,優先使用執行AOF。

  AOF關閉的情況下,才會執行RDB。

   

三、自動間隔性儲存

  save設定:一定條件後執行BGSAVE命令進行儲存

  預設設定:

    save 900 1  //900秒內,進行一次修改,觸發儲存BGSAVE

    save 300 1  //300秒內,10次修改,觸發儲存BGSAVE  

    save 60  10000   //60秒內,1w次修改,觸發儲存BGSAVE 

struct saveparam {
    time_t seconds; //秒數
    int changes;//變化次數
};

還有兩個引數:

dirty --上次資料庫觸發儲存命令修改數   

lastsave -- 最後一次執行save時間

PORT_LONGLONG dirty;                /* Changes to DB from the last save */ 
 time_t lastsave;                /* Unix time of last successful save */

還有一個定時器預設100毫秒來檢測是否滿足save條件的方法:serverCron

int serverCron(struct aeEventLoop *eventLoop, PORT_LONGLONG id, void *clientData) 

 

四、RDB檔案結構 

  | REDIS | db_version | database | EOF | check_sum |

  RDB檔案開頭是REDIS,來判定是否是RDB檔案。

  db_version  版本號

  databse 包含任意多個資料庫(鍵值對)

  EOF RDB檔案結束標誌

  check_sum  校驗長度

 

AOF 持久化

一、命令持久化,儲存redis 的寫命令

二、命令追加

  redis 執行完寫命令,將命令按照一定協議格式追加到 aof_buf 緩衝區

sds aof_buf;      /* AOF buffer, written before entering the event loop */

三、AOF檔案寫入與同步

  resid 伺服器程式是一個事件迴圈

  檔案事件:接受命令和輸出內容

  時間事件:負責定時任務

  檔案事件執行寫命令,這樣會追加命令到aof_buf 緩衝區,在這寫命令結束之前會呼叫flushAppendOnlyFile 函式判斷是否從緩衝區回寫到AOF檔案。

  寫入策略有三個:

    always: 將aof_buf 緩衝區所有內容寫入並同步到AOF檔案。

    everysec(預設): 將緩衝區內容寫入,超過一秒鐘,並進行同步。

    no: 將緩衝區的所有內容同步,但是不同步。

四、AOF 載入以及資料還原

  1、建立一個偽客戶端

  2、分析aof檔案 並解析一條命令

  3、偽客戶端執行此命令

  4、迴圈執行2和3

五、AOF重寫

  AOF 儲存寫命令,體積會膨脹,恢復資料庫的時間也會變長。

  新建檔案AOF ,去除冗餘命令,合併命令。達到縮減檔案目的。

六、AOF後臺重寫

  處理命令請求會因為這個aof重寫造成阻塞。

  另起一個子程式,進行aof重寫。但是會存在資料不一致的問題,子程式在處理重寫一條命令後,同時主程式依然在寫當操作物件的命令。造成資料不一致。

  解決方案:開闢aof重寫快取區

  命令會直接寫入aof快取區和aof重寫快取區,這樣可以讀取快取區命令進行處理。類似佇列,先寫入佇列進行待處理。

  生成的寫命令-->aof緩衝區  -->寫入同步到aof檔案 

  生成的寫命令-->aof重寫緩衝區 -->  寫完  -->傳送訊號給父程式 --> aof重寫緩衝區寫入新aof檔案 -->原子覆蓋舊aof檔案

  

  父程式處理命令,儲存aof,使用子程式,覆蓋重寫aof,達到效能最佳不阻塞,同時生成的新aof也是比較小。

 

相關文章