Redis持久化機制:RDB和AOF

Redis數據持久化

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 ./

觸發快照的時機bash

  • 執行savebgsave命令
  • 配置文件設置save <seconds> <changes>規則,自動間隔性執行bgsave命令
  • 主從複製時,從庫全量複製同步主庫數據,主庫會執行bgsave
  • 執行flushall命令清空服務器數據
  • 執行shutdown命令關閉Redis時,會執行save命令

save和bgsave命令

執行savebgsave命令,能夠手動觸發快照,生成RDB文件,二者的區別以下服務器

使用save命令會阻塞Redis服務器進程,服務器進程在RDB文件建立完成以前是不能處理任何的命令請求app

127.0.0.1:6379> save
OK

而使用bgsave命令不一樣的是,basave命令會fork一個子進程,而後該子進程會負責建立RDB文件,而服務器進程會繼續處理命令請求async

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函數,將一些數據寫入文件時,操做系統一般會將數據暫存到一個內存緩衝區裏,當緩衝區的空間被填滿或超過了指定時限後,才真正將緩衝區的數據寫入到磁盤裏。

這樣的操做雖然提升了效率,但也爲數據寫入帶來了安全問題:若是計算機停機,內存緩衝區中的數據會丟失。爲此,系統提供了fsyncfdatasync同步函數,能夠強制操做系統馬上將緩衝區中的數據寫入到硬盤裏,從而確保寫入數據的安全性。

從上面的介紹咱們知道,咱們寫入的數據,操做系統並不必定會立刻同步到磁盤,因此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-percentageauto-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_bufAOF重寫緩衝區
  • 當子進程完成重寫以後,會給父進程一個信號,而後父進程會把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的優缺點,官網上面也給了比較詳細的說明https://redis.io/topics/persistence

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能夠保證數據的不丟失

相關文章
相關標籤/搜索