Redis持久化背後的故事

Redis持久化

Redis提供了不同的持久化選項:

  • RDB持久化以指定的時間間隔保存那個時間點的數據快照。
  • AOF持久化方法則會記錄每一個服務器收到的寫操作。在服務器啓動時,這些記錄的操作會逐條執行從而重建出原來的數據。寫操作命令記錄的格式跟Redis協議一致,以追加的方式進行保存。
  • Redis的持久化時可以禁用的,就是說你可以讓數據的生命週期只存在服務器的運行時間裏。
  • 兩種方式的持久化是可以同時存在的,但是當Redis重啓時,AOF文件會被優先用於重建數據。

最重要的是要理解RDB和AOF持久化之間的不同區別。

RDB持久化

RDB文件的創建和載入

有兩個Redis命令可以用於生成RDB文件,一個是SAVE,另一個是BGSAVE

SAVE命令會阻塞Redis服務器進程,直到RDB文件創建完畢爲止,在服務器進程阻塞期間,服務器不能處理任何命令請求:

SAVE命令直接阻塞服務器進程的做法不同,BGSAVE命令會去派生出一個子進程,然後由紫禁城負責創建RDB文件,服務器進程(父進程)繼續處理命令請求:

RDB的優勢

  • RDB文件是一個經過壓縮的二進制文件,保存着某個時間點的Redis數據。RDB文件非常適合備份。你可以設定一個時間點對RDB文件進行歸檔,這樣就能在需要的時候很輕易的把數據恢復到不同的版本。
  • RDB非常適用於災備。單文件很方便傳輸到遠程的服務器上。
  • RDB的性能很好,需要進行持久化時,主進程會fork一個子進程出來,然後把持久化工作交給子進程,自己不會有相關的I/O操作,也就是上面說是的BGSAVE
  • 比起AOF,在數據量比較大的情況下,RDB的啓動速度更快。

RDB的缺點

  • RDB容易造成數據的丟失。假設每5分鐘保存一次快照,如果Redis因爲某些原因不能工作,那麼從上次產生快照到Redis出現問題這段時間的數據就會丟失了。上述的SAVE缺點。
  • RDB使用fork()產生子進程進行數據的持久化,如果數據比較大可能就會花費點時間,造成Redis停止服務幾毫秒。如果數據很大且CPU性能不是很好的時候,停止服務的時間甚至更多。上述的BGSAVE缺點。

文件路徑和名稱

默認Redis會把快照文件存儲爲當前目錄下一個名爲dump.rdb的文件。要修改文件的存儲路徑和名稱,可以通過修改配置文件redis.conf實現:

# RDB文件名,默認爲dump.rdb。
dbfilename dump.rdb

# 文件存放的目錄,AOF文件同樣存放在此目錄下。默認爲當前工作目錄。
dir ./

保存點(RDB的啓用和禁用)

你可以配置保存點,使Redis如果在每N秒後數據發生了M次改變就保存快照文件。例如下面這個保存點配置表示每60秒,如果數據發生了1000次以上的變動,Redis就會自動保存快照文件:

save 60 1000

保存點可以設置多個,Redis的配置文件就默認設置了3個保存點:

# 格式爲:save <seconds> <changes>
# 可以設置多個。
save 900 1 #900秒後至少1個key有變動
save 300 10 #300秒後至少10個key有變動
save 60 10000 #60秒後至少10000個key有變動

如果想禁用快照保存的功能,可以通過註釋掉所有"save"配置達到,或者在最後一條"save"配置後添加如下的配置:

save ""

錯誤處理

默認情況下,如果Redis在後臺生成快照的時候失敗,那麼就會停止接收數據,目的是讓用戶能知道數據沒有持久化成功。但是如果你有其他的方式可以監控到Redis及其持久化的狀態,那麼可以把這個功能禁止掉。

stop-writes-on-bgsave-error yes

數據壓縮

默認Redis會採用LZF對數據進行壓縮。如果你想節省點CPU的性能,你可以把壓縮功能禁用掉,但是數據集就會比沒壓縮的時候要打。

rdbcompression yes

數據校驗

從版本5的RDB的開始,一個CRC64的校驗碼會放在文件的末尾。這樣更能保證文件的完整性,但是在保存或者加載文件時會損失一定的性能(大概10%)。如果想追求更高的性能,可以把它禁用掉,這樣文件在寫入校驗碼時會用0替代,加載的時候看到0就會直接跳過校驗。

rdbchecksum yes

AOF持久化

快照並不是很可靠。如果你的電腦突然宕機了,或者電源斷了,又或者不小心殺掉了進程,那麼最新的數據就會丟失。而AOF文件則提供了一種更爲可靠的持久化方式。每當Redis接受到會修改數據集的命令時,就會把命令追加到AOF文件裏,當你重啓Redis時,AOF裏的命令會被重新執行一次,重建數據。

使用AOF持久化需要設置同步選項,從而確保命令同步到磁盤文件上的時機。這是因爲文件進行寫入b並不會馬上將內容同步到磁盤上,而是先存儲到緩衝區,然後由操作系統決定什麼時候同步到磁盤。有以下同步選項:

選項 同步頻率
always 每個寫命令都同步
everysec 每秒同步一次
no 讓操作系統來決定何時同步

優點

  • 比RDB可靠。你可以制定不同的fsync策略:不進行fsync、每秒fsync一次和每次查詢進行fsync。默認是每秒fsync一次。這意味着你最多丟失一秒鐘的數據。
  • AOF日誌文件是一個純追加的文件。就算是遇到突然停電的情況,也不會出現日誌的定位或者損壞問題。甚至如果因爲某些原因(例如磁盤滿了)命令只寫了一半到日誌文件裏,我們也可以用redis-check-aof這個工具很簡單的進行修復。
  • 當AOF文件太大時,Redis會自動在後臺進行重寫。重寫很安全,因爲重寫是在一個新的文件上進行,同時Redis會繼續往舊的文件追加數據。新文件上會寫入能重建當前數據集的最小操作命令的集合。當新文件重寫完,Redis會把新舊文件進行切換,然後開始把數據寫到新文件上。
  • AOF把操作命令以簡單易懂的格式一條接一條的保存在文件裏,很容易導出來用於恢復數據。例如我們不小心用FLUSHALL命令把所有數據刷掉了,只要文件沒有被重寫,我們可以把服務停掉,把最後那條命令刪掉,然後重啓服務,這樣就能把被刷掉的數據恢復回來。

缺點

  • 在相同的數據集下,AOF文件的大小一般會比RDB文件大。
  • 在某些fsync策略下,AOF的速度會比RDB慢。通常fsync設置爲每秒一次就能獲得比較高的性能,而在禁止fsync的情況下速度可以達到RDB的水平。
  • 在過去曾經發現一些很罕見的BUG導致使用AOF重建的數據跟原數據不一致的問題。

啓用AOF

把配置項appendonly設爲yes

appendonly yes

文件路徑和名稱

# 文件存放目錄,與RDB共用。默認爲當前工作目錄。
dir ./

# 默認文件名爲appendonly.aof
appendfilename "appendonly.aof"

可靠性

你可以配置Redis調用fsync的頻率,有三個選項:

  • 每當有新命令追加到AOF的時候調用fsync。速度最慢,但是最安全。
  • 每秒fsync一次。速度快(2.4版本跟快照方式速度差不多),安全性不錯(最多丟失1秒的數據)。
  • 從不fsync,交由系統去處理。這個方式速度最快,但是安全性一般。

推薦使用每秒fsync一次的方式(默認的方式),因爲它速度快,安全性也不錯。相關配置如下:

# appendfsync always
appendfsync everysec
# appendfsync no

日誌重寫

隨着寫操作的不斷增加,AOF文件會越來越大。例如你遞增一個計數器100次,那麼最終結果就是數據集裏的計數器的值爲最終的遞增結果,但是AOF文件裏卻會把這100次操作完整的記錄下來。而事實上要恢復這個記錄,只需要1個命令就行了,也就是說AOF文件裏那100條命令其實可以精簡爲1條。所以Redis支持這樣一個功能:在不中斷服務的情況下在後臺重建AOF文件。

工作原理如下:

  • Redis調用fork(),產生一個子進程。
  • 子進程把新的AOF寫到一個臨時文件裏。
  • 主進程持續把新的變動寫到內存裏的buffer,同時也會把這些新的變動寫到舊的AOF裏,這樣即使重寫失敗也能保證數據的安全。
  • 當子進程完成文件的重寫後,主進程會獲得一個信號,然後把內存裏的buffer追加到子進程生成的那個新AOF裏。
  • Redis

我們可以通過配置設置日誌重寫的條件:

# Redis會記住自從上一次重寫後AOF文件的大小(如果自Redis啓動後還沒重寫過,則記住啓動時使用的AOF文件的大小)。
# 如果當前的文件大小比起記住的那個大小超過指定的百分比,則會觸發重寫。
# 同時需要設置一個文件大小最小值,只有大於這個值文件纔會重寫,以防文件很小,但是已經達到百分比的情況。

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

要禁用自動的日誌重寫功能,我們可以把百分比設置爲0:

auto-aof-rewrite-percentage 0

Redis 2.4以上纔可以自動進行日誌重寫,之前的版本需要手動運行BGREWRITEAOF這個命令。

數據損壞修復

如果因爲某些原因(例如服務器崩潰)AOF文件損壞了,導致Redis加載不了,可以通過以下方式進行修復:

  • 備份AOF文件。

  • 使用redis-check-aof命令修復原始的AOF文件:

    $ redis-check-aof --fix

  • 可以使用diff -u命令看下兩個文件的差異。

  • 使用修復過的文件重啓Redis服務。

從RDB切換到AOF

這裏只說Redis >= 2.2版本的方式:

  • 備份一個最新的dump.rdb的文件,並把備份文件放在一個安全的地方。

  • 運行以下兩條命令:

    $ redis-cli config set appendonly yes
    $ redis-cli config set save ""
  • 確保數據跟切換前一致。

  • 確保數據正確的寫到AOF文件裏。

第二條命令是用來禁用RDB的持久化方式,但是這不是必須的,因爲你可以同時啓用兩種持久化方式。

記得對配置文件redis.conf進行編輯啓用AOF,因爲命令行方式修改配置在重啓Redis後就會失效。

備份

建議的備份方法:

  • 創建一個定時任務,每小時和每天創建一個快照,保存在不同的文件夾裏。
  • 定時任務運行時,把太舊的文件進行刪除。例如只保留48小時的按小時創建的快照和一到兩個月的按天創建的快照。
  • 每天確保一次把快照文件傳輸到數據中心外的地方進行保存,至少不能保存在Redis服務所在的服務器。

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章