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 兩個命令在操作方面並沒有什麼衝突的地方, 不能同時執行它們只是一個性能方面的考慮: 併發出兩個子程序, 並且兩個子程序都同時進行大量的磁碟寫入操作, 這怎麼想都不會是一個好主意。