1. 程式人生 > >redis的持久化(RDB&AOF的區別)

redis的持久化(RDB&AOF的區別)

RDB

是什麼?

  在指定的時間間隔內將記憶體中的資料集快照寫入磁碟,
  也就是行話講的Snapshot快照,它恢復時是將快照檔案直接讀到記憶體裡。
  Redis會單獨建立(fork)一個子程序來進行持久化,會先將資料寫入到一個臨時檔案中,待持久化過程都結束了,再用這個臨時檔案替換上次持久化好的檔案。整個過程中,主程序是不進行任何IO操作的,這就確保了極高的效能
  如果需要進行大規模資料的恢復,且對於資料恢復的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的 缺點 是最後一次持久化後的資料可能丟失。
  rdb 儲存的是dump.rdb檔案

fork:


  fork的作用是複製一個與當前程序一樣的程序。新程序的所有資料(變數、環境變數、程式計數器等)數值都和原程序一致,但是是一個全新的程序,並作為原程序的子程序。

如何觸發RDB快照

  1.配置檔案中預設的快照配置
  2.命令save或者是bgsave
    Save:save時只管儲存,其它不管,全部阻塞
    BGSAVE:Redis會在 後臺非同步 進行快照操作,快照同時還可以響應客戶端請求。可以通過lastsave命令獲取最後一次成功執行快照的時間
  3.執行flushall命令,也會產生dump.rdb檔案,但裡面是空的,無意義

如何恢復

  將備份檔案 (dump.rdb) 移動到 redis 安裝目錄並啟動服務即可。
  CONFIG GET dir獲取目錄。

優勢和劣勢:

優勢:
  1).適合大規模的資料恢復。
  2).對資料完整性和一致性要求不高。
劣勢
  1).在一定間隔時間做一次備份,所以如果redis意外down掉的話,就會丟失最後一次快照後的所有修改。
  2).fork的時候,記憶體中的資料被克隆了一份,大致2倍的膨脹性需要考慮

如何禁止

  動態停止所有RDB儲存規則的方法:redis-cli config set save “”

rdbSave & rdbLoad原理分析

  RDB 功能最核心的是 rdbSave 和 rdbLoad 兩個函式, 前者用於生成 RDB 檔案到磁碟, 而後者則用於將 RDB 檔案中的資料重新載入到記憶體中:
  

儲存rdbSave

  rdbSave 函式負責將記憶體中的資料庫資料以 RDB 格式儲存到磁碟中,如果 RDB 檔案已存在,那麼新的 RDB 檔案將替換已有的 RDB 檔案。
  在儲存 RDB 檔案期間,主程序會被阻塞,直到儲存完成為止。

SAVE 和 BGSAVE 兩個命令都會呼叫 rdbSave 函式,但它們呼叫的方式各有不同:
  SAVE 直接呼叫 rdbSave ,阻塞 Redis 主程序,直到儲存完成為止。在主程序阻塞期間,伺服器不能處理客戶端的任何請求。
  BGSAVE 則 fork 出一個子程序,子程序負責呼叫 rdbSave ,並在儲存完成之後向主程序傳送訊號,通知儲存已完成。因為 rdbSave 在子程序被呼叫,所以 Redis 伺服器在 BGSAVE 執行期間仍然可以繼續處理客戶端的請求。
  通過虛擬碼來描述這兩個命令,可以很容易地看出它們之間的區別:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 def SAVE(): rdbSave()     def BGSAVE(): pid = fork()   if pid == 0: # 子程序儲存 RDB rdbSave()   elif pid > 0: # 父程序繼續處理請求,並等待子程序的完成訊號 handle_request()   else: # pid == -1 # 處理 fork 錯誤 handle_fork_error()

 

載入rdbLoad

  當 Redis 伺服器啟動時, rdbLoad 函式就會被執行, 它讀取 RDB 檔案, 並將檔案中的資料庫資料載入到記憶體中。
  在載入期間, 伺服器每載入 1000 個鍵就處理一次所有已到達的請求, 不過只有 PUBLISH 、 SUBSCRIBE 、 PSUBSCRIBE 、 UNSUBSCRIBE 、 PUNSUBSCRIBE 五個命令的請求會被正確地處理, 其他命令一律返回錯誤。 等到載入完成之後, 伺服器才會開始正常處理所有命令。

  釋出與訂閱功能和其他資料庫功能是完全隔離的,前者不寫入也不讀取資料庫,所以在伺服器載入期間,訂閱與釋出功能仍然可以正常使用,而不必擔心對載入資料的完整性產生影響。

  另外, 因為 AOF 檔案的儲存頻率通常要高於 RDB 檔案儲存的頻率, 所以一般來說, AOF 檔案中的資料會比 RDB 檔案中的資料要新。
  因此, 如果伺服器在啟動時, 打開了 AOF 功能, 那麼程式優先使用 AOF 檔案來還原資料。 只有在 AOF 功能未開啟的情況下, Redis 才會使用 RDB 檔案來還原資料。


AOF(Append Only File)

是什麼:

  以日誌的形式來記錄每個寫操作,將Redis執行過的 所有寫指令 記錄下來(讀操作不記錄),只許追加檔案不可以改寫檔案,redis啟動之初會讀取該檔案重新構建資料,換言之,redis重啟的話就根據日誌檔案的內容將寫指令 從前到後執行一次 以完成資料的恢復工作
  AOF儲存的是appendonly.aof檔案

AOF啟動/修復/恢復

1.正常恢復步驟
  1).修改預設的appendonly no,改為yes
  2).將有資料的aof檔案複製一份儲存到對應目錄(config get dir)
  3).恢復:重啟redis然後重新載入

2.異常恢復步驟
  1).修改預設的appendonly no,改為yes
  2).備份被寫壞的AOF檔案
    redis-check-aof --fix進行修復
  3).恢復:重啟redis然後重新載入

rewrite

1.rewrite是什麼
  AOF採用檔案追加方式,檔案會越來越大。為避免出現此種情況,新增了 重寫機制,當AOF檔案的大小超過所設定的閾值時,Redis就會啟動AOF檔案的內容壓縮,只保留可以恢復資料的最小指令集.可以使用命令bgrewriteaof

2.重寫原理
  AOF檔案持續增長而過大時,會fork出一條新程序來將檔案重寫(也是先寫臨時檔案最後再rename),遍歷新程序的記憶體中資料,每條記錄有一條的Set語句。
  重寫aof檔案的操作,並沒有讀取舊的aof檔案,而是將整個記憶體中的資料庫內容用命令的方式重寫了一個新的aof檔案,這點和快照有點類似

3.觸發機制
  Redis會記錄上次重寫時的AOF大小,預設配置是當AOF檔案大小是上次rewrite後大小的一倍且檔案大於64M時觸發

優勢和劣勢:

優勢
  每修改同步:appendfsync always 同步持久化 每次發生資料變更會被立即記錄到磁碟 效能較差但資料完整性比較好。
  每秒同步:appendfsync everysec 非同步操作,每秒記錄 如果一秒內宕機,有資料丟失
  不同步:appendfsync no 從不同步

劣勢
  相同資料集的資料而言aof檔案要遠大於rdb檔案,恢復速度慢於rdb。
  aof執行效率要慢於rdb,每秒同步策略效率較好,不同步效率和rdb相同


總結(Which one)

  RDB持久化方式能夠在指定的時間間隔能對你的資料進行快照儲存。
  AOF持久化方式記錄每次對伺服器寫的操作,當伺服器重啟的時候會重新執行這些命令來恢復原始的資料,AOF命令以redis協議追加儲存每次寫的操作到檔案末尾。Redis還能對AOF檔案進行後臺重寫,使得AOF檔案的體積不至於過大。
  只做快取:如果你只希望你的資料在伺服器執行的時候存在,你也可以不使用任何持久化方式.

同時開啟兩種持久化方式
  在這種情況下,當redis重啟的時候會優先載入AOF檔案來恢復原始的資料,因為在通常情況下AOF檔案儲存的資料集要比RDB檔案儲存的資料集要完整.
  RDB的資料不實時,同時使用兩者時伺服器重啟也只會找AOF檔案。那要不要只使用AOF呢?建議不要,因為RDB更適合用於備份資料庫(AOF在不斷變化不好備份),快速重啟,而且不會有AOF可能潛在的bug,留著作為一個萬一的手段。

效能建議
  因為RDB檔案只用作後備用途,建議只在Slave上持久化RDB檔案,而且只要15分鐘備份一次就夠了,只保留save 900 1這條規則。
  如果Enalbe AOF,好處是在最惡劣情況下也只會丟失不超過兩秒資料,啟動指令碼較簡單隻load自己的AOF檔案就可以了。代價一是帶來了持續的IO,二是AOF rewrite的最後將rewrite過程中產生的新資料寫到新檔案造成的阻塞幾乎是不可避免的。只要硬碟許可,應該儘量減少AOF rewrite的頻率,AOF重寫的基礎大小預設值64M太小了,可以設到5G以上。預設超過原大小100%大小時重寫可以改到適當的數值。
  如果不Enable AOF ,僅靠Master-Slave Replication 實現高可用性也可以。能省掉一大筆IO也減少了rewrite時帶來的系統波動。代價是如果Master/Slave同時倒掉,會丟失十幾分鐘的資料,啟動指令碼也要比較兩個Master/Slave中的RDB檔案,載入較新的那個。新浪微博就選用了這種架構

SAVE 、 BGSAVE 、 AOF 寫入和 BGREWRITEAOF

  除了瞭解 RDB 檔案的儲存方式之外, 我們可能還想知道, 兩個 RDB 儲存命令能否同時使用? 它們和 AOF 儲存工作是否衝突?
SAVE
  前面提到過, 當 SAVE 執行時, Redis 伺服器是阻塞的, 所以當 SAVE 正在執行時, 新的 SAVE 、 BGSAVE 或 BGREWRITEAOF 呼叫都不會產生任何作用。
  只有在上一個 SAVE 執行完畢、 Redis 重新開始接受請求之後, 新的 SAVE 、 BGSAVE 或 BGREWRITEAOF 命令才會被處理。  
  另外, 因為 AOF 寫入由後臺執行緒完成, 而 BGREWRITEAOF 則由子程序完成, 所以在 SAVE 執行的過程中, AOF 寫入和 BGREWRITEAOF 可以同時進行。

BGSAVE
  在執行 SAVE 命令之前, 伺服器會檢查 BGSAVE 是否正在執行當中, 如果是的話, 伺服器就不呼叫 rdbSave , 而是向客戶端返回一個出錯資訊, 告知在 BGSAVE 執行期間, 不能執行 SAVE 。  
  這樣做可以避免 SAVE 和 BGSAVE 呼叫的兩個 rdbSave 交叉執行, 造成競爭條件。  
  另一方面, 當 BGSAVE 正在執行時, 呼叫新 BGSAVE 命令的客戶端會收到一個出錯資訊, 告知 BGSAVE 已經在執行當中。

BGREWRITEAOF 和 BGSAVE 不能同時執行:
  如果 BGSAVE 正在執行,那麼 BGREWRITEAOF 的重寫請求會被延遲到 BGSAVE 執行完畢之後進行,執行 BGREWRITEAOF 命令的客戶端會收到請求被延遲的回覆。
  如果 BGREWRITEAOF 正在執行,那麼呼叫 BGSAVE 的客戶端將收到出錯資訊,表示這兩個命令不能同時執行。
  BGREWRITEAOF 和 BGSAVE 兩個命令在操作方面並沒有什麼衝突的地方, 不能同時執行它們只是一個性能方面的考慮: 併發出兩個子程序, 並且兩個子程序都同時進行大量的磁碟寫入操作, 這怎麼想都不會是一個好主意。

 

轉自:redis的持久化(RDB&AOF)