Redis持久化機制:RDB和AOF
Redis資料持久化
Redis作為一個記憶體資料庫,資料是以記憶體為載體儲存的,那麼一旦Redis伺服器程式退出,伺服器中的資料也會消失。為瞭解決這個問題,Redis提供了持久化機制,也就是把記憶體中的資料儲存到磁碟當中,避免資料意外丟失
Redis提供了兩種持久化方案:RDB持久化和AOF持久化,一個是快照的方式,一個是類似日誌追加的方式
RDB快照持久化
RDB持久化是通過快照的方式,即在指定的時間間隔內將記憶體中的資料集快照寫入磁碟。在建立快照之後,使用者可以備份該快照,可以將快照複製到其他伺服器以建立相同資料的伺服器副本,或者在重啟伺服器後恢復資料。RDB是Redis預設的持久化方式
快照持久化
RDB持久化會生成RDB檔案,該檔案是一個壓縮過的二進位制檔案,可以通過該檔案還原快照時的資料庫狀態,即生成該RDB檔案時的伺服器資料。RDB檔案預設為當前工作目錄下的dump.rdb
,可以根據配置檔案中的dbfilename
和dir
設定RDB的檔名和檔案位置
# 設定 dump 的檔名
dbfilename dump.rdb
# 工作目錄
# 例如上面的 dbfilename 只指定了檔名,
# 但是它會寫入到這個目錄下。這個配置項一定是個目錄,而不能是檔名。
dir ./
複製程式碼
觸發快照的時機
- 執行
save
和bgsave
命令 - 配置檔案設定
save <seconds> <changes>
bgsave
命令 - 主從複製時,從庫全量複製同步主庫資料,主庫會執行
bgsave
- 執行
flushall
命令清空伺服器資料 - 執行
shutdown
命令關閉Redis時,會執行save
命令
save和bgsave命令
執行save
和bgsave
命令,可以手動觸發快照,生成RDB檔案,兩者的區別如下
使用save
命令會阻塞Redis伺服器程式,伺服器程式在RDB檔案建立完成之前是不能處理任何的命令請求
127.0.0.1:6379> save
OK
複製程式碼
而使用bgsave
命令不同的是,basave
命令會fork
一個子程式,然後該子程式會負責建立RDB檔案,而伺服器程式會繼續處理命令請求
127.0.0.1:6379> bgsave
Background saving started
複製程式碼
fork()
是由作業系統提供的函式,作用是建立當前程式的一個副本作為子程式
fork
一個子程式,子程式會把資料集先寫入臨時檔案,寫入成功之後,再替換之前的RDB檔案,用二進位制壓縮儲存,這樣可以保證RDB檔案始終儲存的是完整的持久化內容
自動間隔觸發
在配置檔案中設定save <seconds> <changes>
規則,可以自動間隔性執行bgsave
命令
################################ SNAPSHOTTING ################################
#
# Save the DB on disk:
#
# save <seconds> <changes>
#
# Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
#
# Note: you can disable saving completely by commenting out all "save" lines.
#
# It is also possible to remove all the previously configured save
# points by adding a save directive with a single empty string argument
# like in the following example:
#
# save ""
save 900 1
save 300 10
save 60 10000
複製程式碼
save <seconds> <changes>
表示在seconds秒內,至少有changes次變化,就會自動觸發gbsave
命令
-
save 900 1
當時間到900秒時,如果至少有1個key發生變化,就會自動觸發bgsave
命令建立快照 -
save 300 10
當時間到300秒時,如果至少有10個key發生變化,就會自動觸發bgsave
命令建立快照 -
save 60 10000
當時間到60秒時,如果至少有10000個key發生變化,就會自動觸發bgsave
命令建立快照
AOF持久化
除了RDB持久化,Redis還提供了AOF(Append Only File)持久化功能,AOF持久化會把被執行的寫命令寫到AOF檔案的末尾,記錄資料的變化。預設情況下,Redis是沒有開啟AOF持久化的,開啟後,每執行一條更改Redis資料的命令,都會把該命令追加到AOF檔案中,這是會降低Redis的效能,但大部分情況下這個影響是能夠接受的,另外使用較快的硬碟可以提高AOF的效能
可以通過配置redis.conf
檔案開啟AOF持久化,關於AOF的配置如下
# appendonly引數開啟AOF持久化
appendonly no
# AOF持久化的檔名,預設是appendonly.aof
appendfilename "appendonly.aof"
# AOF檔案的儲存位置和RDB檔案的位置相同,都是通過dir引數設定的
dir ./
# 同步策略
# appendfsync always
appendfsync everysec
# appendfsync no
# aof重寫期間是否同步
no-appendfsync-on-rewrite no
# 重寫觸發配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 載入aof出錯如何處理
aof-load-truncated yes
# 檔案重寫策略
aof-rewrite-incremental-fsync yes
複製程式碼
AOF的實現
AOF需要記錄Redis的每個寫命令,步驟為:命令追加(append)、檔案寫入(write)和檔案同步(sync)
命令追加(append)
開啟AOF持久化功能後,伺服器每執行一個寫命令,都會把該命令以協議格式先追加到aof_buf
快取區的末尾,而不是直接寫入檔案,避免每次有命令都直接寫入硬碟,減少硬碟IO次數
檔案寫入(write)和檔案同步(sync)
對於何時把aof_buf
緩衝區的內容寫入儲存在AOF檔案中,Redis提供了多種策略
-
appendfsync always
:將aof_buf
緩衝區的所有內容寫入並同步到AOF檔案,每個寫命令同步寫入磁碟 -
appendfsync everysec
:將aof_buf
快取區的內容寫入AOF檔案,每秒同步一次,該操作由一個執行緒專門負責 -
appendfsync no
:將aof_buf
快取區的內容寫入AOF檔案,什麼時候同步由作業系統來決定
appendfsync
選項的預設配置為everysec
,即每秒執行一次同步
關於AOF的同步策略是涉及到作業系統的write
函式和fsync
函式的,在《Redis設計與實現》中是這樣說明的
為了提高檔案寫入效率,在現代作業系統中,當使用者呼叫
write
函式,將一些資料寫入檔案時,作業系統通常會將資料暫存到一個記憶體緩衝區裡,當緩衝區的空間被填滿或超過了指定時限後,才真正將緩衝區的資料寫入到磁碟裡。這樣的操作雖然提高了效率,但也為資料寫入帶來了安全問題:如果計算機停機,記憶體緩衝區中的資料會丟失。為此,系統提供了
fsync
、fdatasync
同步函式,可以強製作業系統立刻將緩衝區中的資料寫入到硬碟裡,從而確保寫入資料的安全性。
從上面的介紹我們知道,我們寫入的資料,作業系統並不一定會馬上同步到磁碟,所以Redis才提供了appendfsync
的選項配置。當該選項時為always
時,資料安全性是最高的,但是會對磁碟進行大量的寫入,Redis處理命令的速度會受到磁碟效能的限制;appendfsync everysec
選項則兼顧了資料安全和寫入效能,以每秒一次的頻率同步AOF檔案,即便出現系統崩潰,最多隻會丟失一秒內產生的資料;如果是appendfsync no
選項,Redis不會對AOF檔案執行同步操作,而是有作業系統決定何時同步,不會對Redis的效能帶來影響,但假如系統崩潰,可能會丟失不定數量的資料
AOF重寫(rewrite)
在瞭解AOF重寫之前,我們先來看看AOF檔案中儲存的內容是啥,先執行兩個寫操作
127.0.0.1:6379> set s1 hello
OK
127.0.0.1:6379> set s2 world
OK
複製程式碼
然後我們開啟appendonly.aof
檔案,可以看到如下內容
*3
$3
set
$2
s1
$5
hello
*3
$3
set
$2
s2
$5
world
複製程式碼
該命令格式為Redis的序列化協議(RESP)。
*3
代表這個命令有三個引數,$3
表示該引數長度為3
看了上面的AOP檔案的內容,我們應該能想象,隨著時間的推移,Redis執行的寫命令會越來越多,AOF檔案也會越來越大,過大的AOF檔案可能會對Redis伺服器造成影響,如果使用AOF檔案來進行資料還原所需時間也會越長
時間長了,AOF檔案中通常會有一些冗餘命令,比如:過期資料的命令、無效的命令(重複設定、刪除)、多個命令可合併為一個命令(批處理命令)。所以AOF檔案是有精簡壓縮的空間的
AOF重寫的目的就是減小AOF檔案的體積,不過值得注意的是:AOF檔案重寫並不需要對現有的AOF檔案進行任何讀取、分享和寫入操作,而是通過讀取伺服器當前的資料庫狀態來實現的
檔案重寫可分為手動觸發和自動觸發,手動觸發執行bgrewriteaof
命令,該命令的執行跟bgsave
觸發快照時類似的,都是先fork
一個子程式做具體的工作
127.0.0.1:6379> bgrewriteaof
Background append only file rewriting started
複製程式碼
自動觸發會根據auto-aof-rewrite-percentage
和auto-aof-rewrite-min-size 64mb
配置來自動執行bgrewriteaof
命令
# 表示當AOF檔案的體積大於64MB,且AOF檔案的體積比上一次重寫後的體積大了一倍(100%)時,會執行`bgrewriteaof`命令
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
複製程式碼
下面看一下執行bgrewriteaof
命令,重寫的流程
- 重寫會有大量的寫入操作,所以伺服器程式會
fork
一個子程式來建立一個新的AOF檔案 - 在重寫期間,伺服器程式繼續處理命令請求,如果有寫入的命令,追加到
aof_buf
的同時,還會追加到aof_rewrite_buf
AOF重寫緩衝區 - 當子程式完成重寫之後,會給父程式一個訊號,然後父程式會把AOF重寫緩衝區的內容寫進新的AOF臨時檔案中,再對新的AOF檔案改名完成替換,這樣可以保證新的AOF檔案與當前資料庫資料的一致性
資料恢復
Redis4.0開始支援RDB和AOF的混合持久化(可以通過配置項 aof-use-rdb-preamble
開啟)
- 如果是redis程式掛掉,那麼重啟redis程式即可,直接基於AOF日誌檔案恢復資料
- 如果是redis程式所在機器掛掉,那麼重啟機器後,嘗試重啟redis程式,嘗試直接基於AOF日誌檔案進行資料恢復,如果AOF檔案破損,那麼用
redis-check-aof fix
命令修復 - 如果沒有AOF檔案,會去載入RDB檔案
- 如果redis當前最新的AOF和RDB檔案出現了丟失/損壞,那麼可以嘗試基於該機器上當前的某個最新的RDB資料副本進行資料恢復
RDB vs AOF
上面介紹了RDB持久化和AOF持久化,那麼來看一下他們各自的優缺點以及該如何選擇持久化方案
RDB和AOF優缺點
關於RDB和AOF的優缺點,官網上面也給了比較詳細的說明redis.io/topics/pers…
RDB
優點:
- RDB快照是一個壓縮過的非常緊湊的檔案,儲存著某個時間點的資料集,適合做資料的備份,災難恢復
- 可以最大化Redis的效能,在儲存RDB檔案,伺服器程式只需fork一個子程式來完成RDB檔案的建立,父程式不需要做IO操作
- 與AOF相比,恢復大資料集的時候會更快
缺點:
- RDB的資料安全性是不如AOF的,儲存整個資料集的過程是比繁重的,根據配置可能要幾分鐘才快照一次,如果伺服器宕機,那麼就可能丟失幾分鐘的資料
- Redis資料集較大時,fork的子程式要完成快照會比較耗CPU、耗時
AOF
優點:
- 資料更完整,安全性更高,秒級資料丟失(取決fsync策略,如果是everysec,最多丟失1秒的資料)
- AOF檔案是一個只進行追加的日誌檔案,且寫入操作是以Redis協議的格式儲存的,內容是可讀的,適合誤刪緊急恢復
缺點:
- 對於相同的資料集,AOF檔案的體積要大於RDB檔案,資料恢復也會比較慢
- 根據所使用的 fsync 策略,AOF 的速度可能會慢於 RDB。 不過在一般情況下, 每秒 fsync 的效能依然非常高
如何選擇RDB和AOF
- 如果是資料不那麼敏感,且可以從其他地方重新生成補回的,那麼可以關閉持久化
- 如果是資料比較重要,不想再從其他地方獲取,且可以承受數分鐘的資料丟失,比如快取等,那麼可以只使用RDB
- 如果是用做記憶體資料庫,要使用Redis的持久化,建議是RDB和AOF都開啟,或者定期執行
bgsave
做快照備份,RDB方式更適合做資料的備份,AOF可以保證資料的不丟失