1. 程式人生 > >Redis持久化之RDB與AOF

Redis持久化之RDB與AOF

Redis是一個記憶體資料庫,他將自己的資料庫狀態儲存在記憶體中,所以,如果不想辦法將記憶體中的資料庫狀態儲存到磁盤裡面,一旦redis伺服器程序退出,伺服器中的資料庫狀態就會消失,為了解決這樣的問題,Redis提供了持久化功能(RDB持久化、AOF持久化),將資料庫狀態儲存儲存在磁碟中,避免了資料的意外丟失。

RDB持久化

RDB持久化既可以手動執行,也可以根據伺服器配置定期執行,將資料庫狀態儲存到一個RDB檔案中,伺服器可以根據載入的RDB檔案,恢復到生成RDB檔案時,資料庫的狀態。redis有兩個命令生成RDB檔案,SAVE和BGSAVE:

  1. SAVE命令,在執行期間,會阻塞Redis伺服器程序,直到RDB檔案建立完畢為止,在伺服器程序阻塞期間,伺服器不能處理任何命令請求。
  2. BGSAVE命令,會派生出一個子程序,然後由子程序負責建立RDB檔案,伺服器程序(父程序)繼續處理命令請求。

伺服器在啟動的時候,根據具體情況選擇載入RDB檔案恢復資料庫狀態,在此期間,伺服器程序會一直處於阻塞狀態,直到載入工作完成為止。

自動間隔性儲存

BGSAVE指令可以在不阻塞伺服器程序的情況下執行,redis可以通過設定伺服器端的save選項讓伺服器每隔一段時間執行一次BGSAVE命令。命令如下:

  1. save 600 1(伺服器在600秒內,對資料庫執行了至少1次修改)
  2. save 900 10(伺服器在900秒內,對資料庫執行了至少10次修改)

可以設定多個條件,,只要滿足任意一個條件,伺服器就會執行BGSAVE命令。如果沒有主動設定儲存條件,伺服器會設定預設的條件:

  1. save 900 1;
  2. save 300 10;
  3. save 60 10000;

伺服器根據save選項設定的儲存條件,設定伺服器狀態,redisService的結構如下:

struct redisServer {
	//...
	//記錄了儲存條件的陣列
	struct saveparam *saveparams;
	//修改計數器
	long long dirty;
	//上一次儲存的時間
	time_t lastsave;
	//...
};

saveparams是一個數組結構,結構如下:

struct saveparam {
	//秒數
	time_t seconds;
	//修改數
	int changes;
};

dirty計數器記錄距離上一次成功執行SAVE命令或者BGSAVE命令之後,伺服器對資料庫進行了多少次修改(包含寫入、刪除、更新等操作) lastsave屬性是一個UNIX時間戳,記錄了伺服器上一次成功執行SAVE和BGSAVE命令的時間。 Redis的伺服器週期性操作函式serverCron預設每隔100毫秒就會執行一次,該函式用於對正在執行的伺服器進行維護,它的其中一項工作就是檢查save選項所設定的儲存條件是否已經滿足,如果滿足的話,就執行BGSAVE命令。 以下虛擬碼展示了serverCron函式檢查儲存條件的過程:

def serverCron():
    # ...
    #遍歷所有儲存條件
for saveparam in server.saveparams:
        #計算距離上次執行儲存操作有多少秒
        save_interval = unixtime_now()-server.lastsave
        #如果資料庫狀態的修改次數超過條件所設定的次數
        #並且距離上次儲存的時間超過條件所設定的時間
        #那麼執行儲存操作
        if server.dirty >= saveparam.changes and \
           save_interval > saveparam.seconds:
            BGSAVE()
    # ...

當BGSAVE執行之後,會重置redisServer中的dirty為0,lastsave為當前時間。

RDB檔案格式

在這裡插入圖片描述

  1. REDIS:常量,儲存著”REDIS”5個字元。
  2. db_version:RDB檔案的版本號。
  3. SELECTDB 0 pairs:表示一個完整的資料庫(0號資料庫),同理SELECTDB 3 pairs表示完整的3號資料庫;只有當資料庫中有鍵值對時,RDB檔案中才會有該資料庫的資訊(上圖所示的Redis中只有0號和3號資料庫有鍵值對);如果Redis中所有的資料庫都沒有鍵值對,則這一部分直接省略。其中:SELECTDB是一個常量,代表後面跟著的是資料庫號碼;0和3是資料庫號碼;pairs則儲存了具體的鍵值對資訊,包括key、value值,及其資料型別、內部編碼、過期時間、壓縮資訊等等。
  4. EOF:常量,標誌RDB檔案正文內容結束。
  5. check_sum:前面所有內容的校驗和;Redis在載入RBD檔案時,會計算前面的校驗和並與check_sum值比較,判斷檔案是否損壞。

AOF持久化

與RDB持久化通過儲存資料庫中的鍵值對來記錄資料庫狀態不同,AOF持久化是通過儲存redis伺服器所執行的寫命令來記錄資料庫狀態。AOF持久化功能的實現可以分為命令追加、檔案寫入、檔案同步三個步驟。 命令追加 當AOF持久化功能開啟時,伺服器在執行完一個寫命令後,將被執行的寫命令追加到伺服器狀態的aof_buf緩衝區的末尾。Redis先將寫命令追加到緩衝區,而不是直接寫入檔案,主要是為了避免每次有寫命令都直接寫入硬碟,導致硬碟IO成為Redis負載的瓶頸。 AOF檔案的寫入和同步 根據不同的同步策略(設定的appendfsync的值),將aof_buf中的內容同步到磁碟中。appendfsync各值的含義:

  1. always,伺服器每個事件迴圈都會將aof_buf緩衝區中的內容寫入到AOF檔案,並且同步AOF檔案,所以always的效率是最低,但安全性是最高的,即使出現機器故障等問題,丟失的資料量越是最少的。
  2. no,伺服器每個事件迴圈,都會將aof_buf緩衝區的內容寫到AOF檔案中,至於何時對AOF檔案進行同步,則由作業系統控制。
  3. everysec,伺服器每個事件迴圈,都會將aof_buf緩衝區的內容寫到AOF檔案中,並且每隔1秒鐘,對AOF檔案同步一次,效率與設定為no是相近,資料安全性較高,機器出現故障,只會丟失一秒鐘的資料。 AOF檔案載入 AOF檔案中儲存的是重建資料庫所需的所有的寫命令,所以伺服器啟動後,只需要將檔案迴圈執行AOF裡的寫命令,就可以恢復資料庫的狀態。 AOF檔案重寫 AOF檔案裡儲存的是所有的寫命令,隨著時間的推移,AOF檔案會越來越大,為了解決這樣的問題,redis提供了AOF檔案重寫功能。AOF檔案重寫,不會對於現有的AOF檔案進行任何的讀取、分析和寫入操作,而是新建一個檔案,通過讀取伺服器當前資料庫狀態,儲存寫入命令,新舊兩個AOF檔案,索堡村的資料庫狀態是完全相同的,但是,新的AOF檔案中不會包含任何浪費空間的冗餘資料,所以新的AOF檔案的大小會小很多。

RDB與AOF的選擇

RDB持久化唯一,也是最大的缺點就是其資料快照的持久化方式,必然做不到實時的持久化,在很多業務場景中,資料丟失是不能接受的,