本文首發於 Redis 持久化(persistence)技術口袋書,轉載請註明出處。
本文講解 Redis 資料庫的資料持久化解決方案。
測試環境:
- Windows 7
- Redis 4.0.2.2 去下載 Windows 版本
RDB 和 AOF 持久化解決方案
Redis 提供兩種持久化解決方案:RDB 持久化和 AOF 持久化。
要點:
RDB 持久化:可以在指定時間間隔內,生成資料集在這個時間點的快照。
AOF 持久化:通過記錄伺服器執行的所有寫操作命令,在伺服器重啟時,通過重新執行這些命令來還原資料。
RDB 持久化方案
採用 RDB 持久化方案時,Redis 會每隔一段時間對資料集進行快照備份,換句話說這種方案在伺服器發生故障時可能造成資料的丟失。所以,如果對資料的完整性有比較強烈的要求,可能不太適用這種備份方案,即它適用於做資料的備份。
執行持久化策略
- 自動執行 RDB 持久化
我們已經知道,採用 RDB 持久化方案會每隔一段時間對資料進行備份,那麼這個時間段如何確定呢?
我們可以到 redis.windows.conf 配置檔案的 SNAPSHOTTING 配置節點獲取答案,預設情況下 Redis 採用三種持久化策略:
save 900 1
save 300 10
save 60 10000
這裡的 save 指令表示「在 x 秒內有 n 個及以上鍵被改動」則會自動儲存一次資料集,比如配置中的 save 60 10000 表示如果在 60 秒內有 10000 個及以上的鍵被改動時則執行儲存資料集操作。
我們在啟動 Redis 服務時,伺服器會讀取配置檔案中的配置,所以 RDB 持久化策略會自動啟動,當滿足條件時會執行持久化處理。
- 手動執行 RDB 持久化
不過,有時我們可能需要手動的執行 RDB 持久化處理,那麼 Redis 有沒有提供類似的方法呢?
答案是有的,我們可以使用 [SAVE]](http://redisdoc.com/server/save.html)(這裡不是配置檔案中的 save 指令) 或 BGSAVE 命令,來手動執行 RDB 持久化處理。
雖然,save 和 bgsave 都可以手動的執行 RDB 持久化處理。但是它們的工作模式完全不同。
- 執行 SAVE 命令時,會阻塞 Redis 主程式,直到儲存完成為止。在主程式阻塞期間,伺服器不能處理客戶端的任何請求。
- BGSAVE 則 fork 出一個子程式,子程式負責執行儲存處理,並在儲存完成之後向主程式傳送訊號,通知主程式儲存完成。所以 Redis 伺服器在 BGSAVE 執行期間仍然可以繼續處理客戶端的請求。
注意:雖然通過 SAVE 命令可以執行 RDB 持久化處理,但是它的執行原理同自動持久化中的 save 指令是完全不同的,save 指令的工作原理同 BGSAVE 指令。
快照(SNAPSHOTTING)
在 RDB 持久化策略中,我們引入了「快照」的概念,即「在 x 秒內有 n 個及以上鍵被改動」則執行持久化處理。
寫時複製(copy-on-write):快照的執行原理
- Redis 呼叫 fork() ,同時擁有父程式和子程式。
- 子程式將資料集寫入到一個臨時 RDB 檔案中。
- 當子程式完成對新 RDB 檔案的寫入時,Redis 用新 RDB 檔案替換原來的 RDB 檔案,並刪除舊的 RDB 檔案。
摘自 Redis 持久化。
優點
- RDB 是一個非常緊湊(compact)的檔案(筆者注:因為 RDB 持久化檔案 dump.rdb 將資料集以二級制形式儲存),它儲存了 Redis 在某個時間點上的資料集。 這種檔案非常適合用於進行備份。
- RDB 非常適用於災難恢復(disaster recovery):它只有一個檔案,並且內容都非常緊湊,可以(在加密後)將它傳送到別的資料中心,或者亞馬遜 S3 中。
- RDB 可以最大化 Redis 的效能:父程式在儲存 RDB 檔案時唯一要做的就是 fork 出一個子程式,然後這個子程式就會處理接下來的所有儲存工作,父程式無須執行任何磁碟 I/O 操作。
- RDB 在恢復大資料集時的速度比 AOF 的恢復速度要快。
缺點
- 可能在伺服器故障時導致資料丟失,因為 RDB 採用的是定時儲存資料的機制,所以可能導致下次儲存資料時的資料丟失。
- 可能導致伺服器無法處理客戶端處理,這是由於 RDB 執行非阻塞(BGSAVE 或 save 指令)儲存時,會 fock 出子程式,如果待儲存的資料集非常大可能會非常耗時。
AOF 持久化方案
通過 RDB 持久化方案的學習,我們知道它可能導致資料丟失,如果你的專案忍不了資料丟失的問題,那麼可能就需要使用 AOF 持久化方案。
AOF(append only file):只進行追加操作的檔案。預設情況下,Redis 會禁用 AOF 重寫,無需開啟我們需要到配置檔案中將 appendonly 指令配置為 yes(預設:no 不啟用)。
啟用 AOF 持久化方案後,當我們執行類似 SET 設定(或修改)命令時,Redis 會將命令以 Redis 通訊協議 文字儲存到 appendonly.aof 檔案中。
執行持久化策略
AOF 持久化方案提供 3 種不同時間策略將資料同步到磁碟中,同步策略通過 appendfsync 指令完成:
- everysec(預設):表示每秒執行一次 fsync 同步策略,效率上同 RDB 持久化差不多。由於每秒同步一次,所以伺服器故障時會丟失 1 秒內的資料。
- always: 每個寫命令都會呼叫 fsync 進行資料同步,最安全但影響效能。
- no: 表示 Redis 從不執行 fsync,資料將完全由核心控制寫入磁碟。對於 Linux 系統來說,每 30 秒寫入一次。
使用是推薦採用預設的 everysec 每秒同步策略,兼顧安全與效率。
寫時複製(copy-on-write):AOF 持久化的執行原理
- Redis 主程式執行 fork() 建立出子程式。
- 子程式開始將新 AOF 檔案的內容寫入到臨時檔案。
- 對於所有新執行的寫入命令,父程式一邊將它們累積到一個記憶體快取中,一邊將這些改動追加到現有 AOF 檔案的末尾: 這樣即使在重寫的中途發生停機,現有的 AOF 檔案也還是安全的。
- 當子程式完成重寫工作時,它給父程式傳送一個訊號,父程式在接收到訊號之後,將記憶體快取中的所有資料追加到新 AOF 檔案的末尾。
- 搞定!現在 Redis 原子地用新檔案替換舊檔案,之後所有命令都會直接追加到新 AOF 檔案的末尾。
摘自 Redis 持久化。
優化 AOF 備份檔案
我們知道 AOF 的執行原理是不斷的將寫入的命令以 Redis 通訊協議的資料格式追加到 .aof 檔案末尾,這就會導致檔案的體積不斷增大。
如果所有的命令完全不同到沒有關係。
但是,如果命令處理類似計數器的功能,比如執行 100 次 INCR(incr counter) 處理,AOF 檔案會儲存全部的 INCR 命令的執行記錄,但實際上我們知道這些處理的結果同 set counter 100 並無二致。這就導致我們的 .aof 多儲存了 99 條命令記錄。
這時,我們就可以使用 Redis 提供的 BGREWRITEAOF 重寫命令,將 AOF 檔案進行重寫優化。
舉例:
SET name 'liugongzi'
SET age 18
SET name 'liugongzi handsome'
AOF 檔案將這些寫入命令儲存到(appendonly.aof)檔案中,內容如下:
*2
$6
SELECT
$1
0
*3
$3
set
$4
name
$9
liugongzi
*3
$3
set
$3
age
$2
18
*3
$3
set
$4
name
$18
liugongzi handsome
寫入的內容完全遵循 Redis 通訊協議。通過示例,我們知道雖然我們執行了兩次 set name 操作,但最終 Redis 儲存的 name 值是 liugongzi handsome。也就是說第一次 set name 其實並無必要。
現在我們通過 BGREWRITEAOF 命令對檔案進行重寫處理:
127.0.0.1:6380> BGREWRITEAOF
Background append only file rewriting started
重寫完成後的 AOF 檔案內容如下:
*2
$6
SELECT
$1
0
*3
$3
SET
$3
age
$2
18
*3
$3
SET
$4
name
$18
liugongzi handsome
通過對比重寫前後的檔案內容,可以發現 Redis 將第一次的 set name 'liugongzi' 操作給刪出掉了。這樣就達到優化 AOF 檔案的目的。
補充一句 AOF 重寫,並不是對 AOF 檔案進行重寫,而是依據 Redis 在記憶體中當前的鍵值進行重寫的。
優點
- 提供比 RDB 持久化方案更安全的資料,由於預設採用每秒進行持久化處理,所有即使伺服器重啟或當機,最多也就丟失 1 秒內的資料。
- AOF 檔案有序地儲存了對資料庫執行的所有寫入操作, 這些寫入操作以 Redis 協議的格式儲存, 因此 AOF 檔案的內容非常容易被人讀懂, 對檔案進行分析(parse)也很輕鬆
缺點
- 相比於 RDB 持久化,AOF 檔案會比 RDB 備份檔案大得多。
- AOF 持久化的速度可能比 RDB 持久化速度慢。
- AOF 在過去曾經發生過這樣的 bug : 因為個別命令的原因,導致 AOF 檔案在重新載入時,無法將資料集恢復成儲存時的原樣。 (舉個例子,阻塞命令 BRPOPLPUSH 就曾經引起過這樣的 bug 。) 測試套件裡為這種情況新增了測試: 它們會自動生成隨機的、複雜的資料集, 並通過重新載入這些資料來確保一切正常。 雖然這種 bug 在 AOF 檔案中並不常見, 但是對比來說, RDB 幾乎是不可能出現這種 bug 的。
摘自 Redis 持久化。
Redis 資料恢復
通過前面的學習我們瞭解到 Redis 是如何執行 RDB 和 AOF 持久化處理的,現在我們簡單瞭解下 Redis 是如何恢復 RDB 或 AOF 備份中的資料。
我們知道 Redis 是一種記憶體型的 NoSQL 資料庫(或者說資料結構),當服務重啟或當機都會導致記憶體中的資料丟失。
所以,當 Redis 伺服器重啟或恢復時,它會進行讀取 RDB 或 AOF 檔案(如果存在的話)處理,將檔案中的資料重新載入記憶體實現資料恢復操作。
Redis 資料恢復採用兩套恢復方案:
- 開啟 AOF 持久化方案時,優先採用 AOF 檔案進行資料恢復
這個很好理解,因為 AOF 持久化方案的資料儲存是秒級的,所以相對於 RDB 持久化資料更完整,所以在啟動 Redis 伺服器是,會在 AOF 啟用時有限載入 AOF 檔案進行資料還原。
- 未開啟 AOF 持久化方案是,Redis 通過載入 RDB 檔案進行資料恢復
RDB 持久化配置
到這裡,相信你對 Redis 持久化已經有了相當大瞭解了,這節開始我們將學習 Redis 配置檔案,看看如何使用 RDB 和 AOF 持久化功能。
Redis 伺服器配置檔案預設是 redis.windows.conf:
RDB 持久化配置選項
RDB 配置位於 SNAPSHOTTING 配置節點。
- 開啟 / 關閉 RDB 持久化功能
- 嚴格來說 Redis 沒有提供類似 AOF 的 appendonly 指令來開啟 RDB 持久化功能,我們可以通過註釋掉 save 指令來關閉 RDB 備份方案。
#save 900 1
#save 300 10
#save 60 10000
- 或者使用 config set save "" 命令來關閉重寫,但是如果僅使用這條命令,僅在當前伺服器執行時生效,所以重啟伺服器依然從配置檔案讀取 RDB 重寫規則。如果想永久生效,可以執行 config rewrite 命令,將 config set save 命令結果寫入到配置檔案。執行完 config rewrite 命令後會直接刪除 redis.windows.conf 配置中的 save 指令。
- 是否啟用壓縮
通過 rdbcompression 指令完成,預設 yes 進行壓縮。
- 修改備份檔名
使用 dbfilename 指令,預設值 dump.rdb。
- 修改備份檔案儲存目錄
使用 dir 指令,預設值 your_redis_path。另外 AOF 備份資料同樣會儲存到該目錄下。
AOF 持久化配置選項
AOF 配置位於 APPEND ONLY MODE 配置節點。
- 開啟 / 關閉 AOF 持久化功能
開啟 AOF 持久化功能,通過 appendonly 指令完成,取值範圍 yes / no,預設:no 不開啟 AOF 重寫。
- 修改備份檔名
由 appendfilename 指令完成,預設值 appendonly.aof。
- 設定持久化執行策略
請參考前文 appendfsync 指令說明。
- AOF 備份檔案重寫規則配置
之前我們通過使用命令 BGREWRITEAOF 對 AOF 執行重寫,但是當我們啟用 AOF 持久化功能後,Redis 預設會啟用 AOF 重寫優化,這個工作有兩條指令完成:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
auto-aof-rewrite-percentage 指令表示,本次執行 AOF 重寫時,當 AOF 檔案的大小是上次執行重寫時檔案的百分之多少才可以自動重寫。預設: 100 表示本次重寫時的 AOF 檔案是上次 2 倍可以自動重寫。
auto-aof-rewrite-min-size 這個指令用於設定進行 AOF 檔案自動重寫的最小檔案大小。
換言之,這兩條配置表示:當 AOF 檔案大小達到 64mb 時,才開始自動進行重寫。下一次只有當檔案大小需達到 128 mb 才能再次重寫,以此類推。
- 自動修復出錯的 AOF 資料
當我們的 Redis 伺服器當機時,可能導致 AOF 檔案的尾部資料不完整,在重啟 Redis 伺服器可能導致資料不一致。此時可以通過:
aof-load-truncated 指令在啟動 Redis 自動修復檔案。它的取值範圍是 yes / no,預設為 yes 重啟時自動修復。
同樣的我們也可以通過 redis-check-aof --fix 修復工具手動進行修復。
參考資料
NoSQL 之【Redis】學習(三):Redis 持久化 Snapshot 和 AOF 說明
本作品採用《CC 協議》,轉載必須註明作者和本文連結