《Redis官方文件》持久化

ali清英發表於2016-04-01

原文連結 譯者:Alexandar Mahone

這篇文章從技術層面描述了Redis持久化,建議所有讀者閱讀。如果希望更多瞭解Redis持久化和永續性保障,建議閱讀Redis持久化揭祕

Redis 持久化

提供了多種不同級別的持久化方式:

  • RDB 持久化可以在指定的時間間隔內生成資料集的時間點快照(point-in-time snapshot)。
  • AOF 持久化記錄伺服器執行的所有寫操作命令,並在伺服器啟動時,通過重新執行這些命令來還原資料集。 AOF 檔案中的命令全部以 Redis 協議的格式來儲存,新命令會被追加到檔案的末尾。 Redis 還可以在後臺對 AOF 檔案進行重寫(rewrite),使得 AOF 檔案的體積不會超出儲存資料集狀態所需的實際大小。Redis 還可以同時使用 AOF 持久化和 RDB 持久化。 在這種情況下, 當 Redis 重啟時, 它會優先使用 AOF 檔案來還原資料集, 因為 AOF 檔案儲存的資料集通常比 RDB 檔案所儲存的資料集更完整。你甚至可以關閉持久化功能,讓資料只在伺服器執行時存在。

瞭解 RDB 持久化和 AOF 持久化之間的異同是非常重要的, 以下幾個小節將詳細地介紹這這兩種持久化功能, 並對它們的相同和不同之處進行說明。

RDB 的優點:

  • RDB是一種表示某個即時點的Redis資料的緊湊檔案。RDB檔案適合用於備份。例如,你可能想要每小時歸檔最近24小時的RDB檔案,每天儲存近30天的RDB快照。這允許你很容易的恢復不同版本的資料集以容災。
  • RDB非常適合於災難恢復,作為一個緊湊的單一檔案,可以被傳輸到遠端的資料中心,或者是Amazon S3(可能得加密)。
  • RDB最大化了Redis的效能,因為Redis父程式持久化時唯一需要做的是啟動(fork)一個子程式,由子程式完成所有剩餘工作。父程式例項不需要執行像磁碟IO這樣的操作。
  • RDB在重啟儲存了大資料集的例項時比AOF要快。

RDB 的缺點

  • 當你需要在Redis停止工作(例如停電)時最小化資料丟失,RDB可能不太好。你可以配置不同的儲存點(save point)來儲存RDB檔案(例如,至少5分鐘和對資料集100次寫之後,但是你可以有多個儲存點)。然而,你通常每隔5分鐘或更久建立一個RDB快照,所以一旦Redis因為任何原因沒有正確關閉而停止工作,你就得做好最近幾分鐘資料丟失的準備了。
  • RDB需要經常呼叫fork()子程式來持久化到磁碟。如果資料集很大的話,fork()比較耗時,結果就是,當資料集非常大並且CPU效能不夠強大的話,Redis會停止服務客戶端幾毫秒甚至一秒。AOF也需要fork(),但是你可以調整多久頻率重寫日誌而不會有損(trade-off)永續性(durability)。

AOF 的優點:

  • 使用AOF Redis會更具有可永續性(durable):你可以有很多不同的fsync策略:沒有fsync,每秒fsync,每次請求時fsync。使用預設的每秒fsync策略,寫效能也仍然很不錯(fsync是由後臺執行緒完成的,主執行緒繼續努力地執行寫請求),即便你也就僅僅只損失一秒鐘的寫資料。
  • AOF日誌是一個追加檔案,所以不需要定位,在斷電時也沒有損壞問題。即使由於某種原因檔案末尾是一個寫到一半的命令(磁碟滿或者其他原因),redis-check-aof工具也可以很輕易的修復。
  • 當AOF檔案變得很大時,Redis會自動在後臺進行重寫。重寫是絕對安全的,因為Redis繼續往舊的檔案中追加,使用建立當前資料集所需的最小操作集合來建立一個全新的檔案,一旦第二個檔案建立完畢,Redis就會切換這兩個檔案,並開始往新檔案追加。
  • AOF檔案裡面包含一個接一個的操作,以易於理解和解析的格式儲存。你也可以輕易的匯出一個AOF檔案。例如,即使你不小心錯誤地使用FLUSHALL命令清空一切,如果此時並沒有執行重寫,你仍然可以儲存你的資料集,你只要停止伺服器,刪除最後一條命令,然後重啟Redis就可以。

AOF 的缺點:

  • 對同樣的資料集,AOF檔案通常要大於等價的RDB檔案。
  • AOF可能比RDB慢,這取決於準確的fsync策略。通常fsync設定為每秒一次的話效能仍然很高,如果關閉fsync,即使在很高的負載下也和RDB一樣的快。不過,即使在很大的寫負載情況下,RDB還是能提供能好的最大延遲保證。
  • 在過去,我們經歷了一些針對特殊命令(例如,像BRPOPLPUSH這樣的阻塞命令)的罕見bug,導致在資料載入時無法恢復到儲存時的樣子。這些bug很罕見,我們也在測試套件中進行了測試,自動隨機創造複雜的資料集,然後載入它們以檢查一切是否正常,但是,這類bug幾乎不可能出現在RDB持久化中。為了說得更清楚一點:Redis AOF是通過遞增地更新一個已經存在的狀態,像MySQL或者MongoDB一樣,而RDB快照是一次又一次地從頭開始創造一切,概念上更健壯。但是,1)要注意Redis每次重寫AOF時都是以當前資料集中的真實資料從頭開始,相對於一直追加的AOF檔案(或者一次重寫讀取老的AOF檔案而不是讀記憶體中的資料)對bug的免疫力更強。2)我們還沒有收到一份使用者在真實世界中檢測到崩潰的報告。

RDB 和 AOF ,我應該用哪一個?

一般來說,如果想達到足以媲美 PostgreSQL 的資料安全性, 你應該同時使用兩種持久化功能。

如果你非常關心你的資料,但仍然可以承受數分鐘以內的資料丟失, 那麼你可以只使用 RDB 持久化。

有很多使用者單獨使用AOF,但是我們並不鼓勵這樣,因為時常進行RDB快照非常方便於資料庫備份,啟動速度也較之快,還避免了AOF引擎的bug。

注意:基於這些原因,將來我們可能會統一AOF和RDB為一種單一的持久化模型(長遠計劃)。

下面的部分將介紹兩種持久化模型等多的細節。

RDB 快照

預設情況下,Redis儲存資料集快照到磁碟,名為dump.rdb的二進位制檔案。你可以設定讓Redis在N秒內至少有M次資料集改動時儲存資料集,或者你也可以手動呼叫SAVE或者BGSAVE命令。

例如,這個配置會讓Redis在每個60秒內至少有1000次鍵改動時自動轉儲資料集到磁碟:

save 60 1000

這種策略被稱為快照。

快照的運作方式:

當 Redis 需要儲存 dump.rdb 檔案時, 伺服器執行以下操作:

  • Redis 呼叫 fork() ,同時擁有父程式和子程式。
  • 子程式將資料集寫入到一個臨時 RDB 檔案中。
  • 當子程式完成對新 RDB 檔案的寫入時,Redis 用新 RDB 檔案替換原來的 RDB 檔案,並刪除舊的 RDB 檔案。

這種工作方式使得 Redis 可以從寫時複製(copy-on-write)機制中獲益。

只追加檔案 AOF

快照功能並不是非常耐久(durable): 如果 Redis 因為某些原因而造成故障停機, 那麼伺服器將丟失最近寫入、且仍未儲存到快照中的那些資料。儘管對於某些程式來說, 資料的耐久性並不是最重要的考慮因素, 但是對於那些追求完全耐久能力(full durability)的程式來說, 快照功能就不太適用了。

從 1.1 版本開始, Redis 增加了一種完全耐久的持久化方式: AOF 持久化。

你可以通過修改配置檔案來開啟 AOF 功能:
appendonly yes
從現在開始, 每當 Redis 執行一個改變資料集的命令時(比如 SET), 這個命令就會被追加到 AOF 檔案的末尾。 當 Redis 重新啟時, 程式就可以通過重新執行 AOF 檔案中的命令來達到重建資料集的目的。

日誌重寫

你可以猜得到,寫操作不斷執行的時候AOF檔案會越來越大。例如,如果你增加一個計數器100次,你的資料集裡只會有一個鍵儲存這最終值,但是卻有100條記錄在AOF中。其中99條記錄在重建當前狀態時是不需要的。

於是Redis支援一個有趣的特性:在後臺重建AOF而不影響服務客戶端。每當你傳送BGREWRITEAOF時,Redis將會寫入一個新的AOF檔案,包含重建當前記憶體中資料集所需的最短命令序列。如果你使用的是Redis 2.2的AOF,你需要不時的執行BGREWRITEAOF命令。Redis 2.4可以自動觸發日誌重寫(檢視Redis 2.4中的示例配置檔案以獲得更多資訊)。

AOF永續性如何?

你可以配置 Redis 多久才將資料 fsync 到磁碟一次。有三個選項:

  • 每次有新命令追加到 AOF 檔案時就執行一次 fsync :非常慢,也非常安全。
  • 每秒 fsync 一次:足夠快(和使用 RDB 持久化差不多),並且在故障時只會丟失 1 秒鐘的資料。
  • 從不 fsync :將資料交給作業系統來處理。更快,也更不安全的選擇。

推薦(並且也是預設)的措施為每秒 fsync 一次, 這種 fsync 策略可以兼顧速度和安全性。 總是 fsync 的策略在實際使用中非常慢, 即使在 Redis 2.0 對相關的程式進行了改進之後仍是如此 —— 頻繁呼叫 fsync 註定了這種策略不可能快得起來。

如果 AOF 檔案出錯了,怎麼辦?

伺服器可能在程式正在對 AOF 檔案進行寫入時崩潰(這個不應該破壞資料的一致性), Redis不會裝載已破壞的AOF檔案。當發生這種情況時, 可以用以下方法來修復出錯的 AOF 檔案:

  • 為現有的 AOF 檔案建立一個備份。
  • 使用 Redis 附帶的 redis-check-aof 程式,對原來的 AOF 檔案進行修復。
  • $ redis-check-aof –fix
  • (可選)使用 diff -u 對比修復後的 AOF 檔案和原始 AOF 檔案的備份,檢視兩個檔案之間的不同之處。
  • 重啟 Redis 伺服器,等待伺服器載入修復後的 AOF 檔案,並進行資料恢復。

如何工作

日誌重寫採用了和快照一樣的寫時複製機制。下面是過程:

  • Redis呼叫fork()。於是我們有了父子兩個程式。
  • 子程式開始向一個臨時檔案中寫AOF。
  • 父程式在一個記憶體緩衝區中積累新的變更(同時將新的變更寫入舊的AOF檔案,所以即使重寫失敗我們也安全)。
  • 當子程式完成重寫檔案,父程式收到一個訊號,追加記憶體緩衝區到子程式建立的檔案末尾。
  • 搞定!現在Redis原子性地重新命名舊檔案為新的,然後開始追加新資料到新檔案。

如何由RDB持久化轉換到AOF持久化?

Redis 2.0 和 Redis 2.2 處理流程不一樣,可以很簡單猜測到 Redis 2.2 處理流程更簡單,並且不需要重啟。

Redis >=2.2 時

  • 建立最近的RDB檔案的備份。
  • 將備份儲存在安全的位置。
  • 發起如下命令。
  • $redis-cli config set appendonly yes。
  • $redis-cli config set save “”。
  • 確認資料庫包含相同的keys。
  • 確認write操作被正確追加到了AOF檔案。

第一個CONFIG命令開啟AOF。Redis會阻塞以生成初始轉儲檔案,然後開啟檔案準備寫,開始追加寫操作。

第二個CONFIG命令用於關閉快照持久化。這一步是可選的,如果你想同時開啟這兩種持久化方法。

重要:記得編輯你的redis.conf檔案來開啟AOF,否則當你重啟伺服器時,你的配置修改將會丟失,伺服器又會使用舊的配置。

Redis2.0時

  • 建立最近的RDB檔案的備份;
  • 將備份存放在安全的位置;
  • 停止資料庫上的所有寫操作;
  • 發起 redis-cli bgrewriteaof命令建立AOF檔案;
  • 當AOF檔案生成後停止Redis Server;
  • 編輯redis.conf開啟AOF持久化;
  • 重啟Redis Server;
  • 確認資料庫包含相同的keys;
  • 確認write操作被正確追加到了AOF檔案。

AOF與RDB之間的相互作用

Redis2.4以上的版本會確保在RDB快照建立時不觸發AOF重寫或者在AOF重寫時不允許BGSAVE操作,以避免Redis後臺程式同時做繁重的磁碟I/O操作。

當建立RDB快照時對於使用者使用BGREWRITEAOF明確發起的日誌重寫操作server會立刻回應一個ok狀態碼告知使用者操作將回被執行,當且僅當快照建立完成後重寫操作開始被執行。

在同時使用了AOF和RDB方式的情況下,Redis重啟後會優先使用AOF檔案來重構原始資料集。

備份Redis 資料

開始這一部分之前,請務必牢記:一定要備份你的資料庫。磁碟損壞,雲中例項丟失,等等:沒有備份意味著丟失資料的巨大風險。

Redis對資料備份非常友好,因為你可以在資料庫執行時拷貝RDB檔案:RDB檔案一旦生成就不會被修改,檔案生成到一個臨時檔案中,當新的快照完成後,將原子性地使用rename(2)修改檔名為目標檔案。

這意味著,在伺服器執行時拷貝RDB檔案是完全安全的。以下是我們的建議:

  • 建立一個定時任務(cron job),每隔一個小時建立一個RDB快照到一個目錄,每天的快照放在不同目錄。
  • 每次定時指令碼執行時,務必使用find命令來刪除舊的快照:例如,你可以儲存最近48小時內的每小時快照,一到兩個月的內的每天快照。注意命名快照時加上日期時間資訊。
  • 至少每天一次將你的RDB快照傳輸到你的資料中心之外,或者至少傳輸到執行你的Redis例項的物理機之外。

災難恢復

在Redis中災難恢復和資料備份基本上是同樣的過程,並且災難恢復會將這些備份傳輸到外部的多個資料中心。這樣即使一些災難性的事件影響到執行Redis和生成快照的主資料中心,資料也是安全的。

由於許多Redis使用者都處於啟動階段,沒有太多預算,我們會介紹一些最有意思的災難恢復技術,而不用太多的花銷。

  • Amazon S3和一些類似的服務是幫助你災難恢復系統的一個好辦法。很簡單,只需要將你的每日或每小時的RDB快照以加密的方式傳輸到S3。你可以使用 gpg -c 來加密你的資料(以對稱加密模式)。確保將你的密碼儲存在不同的安全地方(例如給一份到你的組織中的最重要的人)。推薦使用多個儲存服務以提升資料安全。
  • 使用SCP(SSH的組成部分)來傳輸你的快照到遠端伺服器。這是一種相當簡單和安全的方式:在遠離你的位置獲得一個小的VPS,安裝ssh,生成一個無口令的ssh客戶端key,並將其新增到你的VPS上的authorized_keys檔案中(譯者注:這是SSH互信,在Linux系統中可以使用ssh-keygen命令生成公私鑰)。你就可以自動的傳輸備份檔案了,無需輸入密碼。為了達到更好的效果,最好是至少從不同的提供商那搞兩個VPS。

要知道這種系統如果沒有正確的處理會很容易失敗。至少一定要確保傳輸完成後驗證檔案的大小(要匹配你拷貝的檔案),如果你使用VPS的話,可以使用 SHA1 數字簽名。

你還需要一個獨立的告警系統,在某些原因導致傳輸備份過程失敗時告警。 


相關文章