天天看點

Redis持久化RDB&AOF

RDB快照(Redis DataBase)

RDB是一種快照存儲持久化方式,具體就是将Redis某一時刻的記憶體資料儲存到硬碟的檔案當中,預設儲存的檔案名為dump.rdb,而在Redis伺服器啟動時,會重新加載dump.rdb檔案的資料到記憶體當中恢複資料。

開啟RDB持久化方式

開啟RDB持久化方式很簡單,用戶端可以通過向Redis伺服器發送save或bgsave指令讓伺服器生成rdb檔案,或者通過伺服器配置檔案指定觸發RDB條件。每次執行都會将所有redis記憶體快照到一個新的rdb檔案裡,并覆寫原有rdb快照檔案。

方式一:save指令

# 同步資料到磁盤上
> save      
Redis持久化RDB&AOF

當用戶端向伺服器發送save指令請求進行持久化時,伺服器會阻塞save指令之後的其他用戶端的請求,直到資料同步完成。 如果資料量太大,同步資料會執行很久,而這期間Redis伺服器也無法接收其他請求,是以,最好不要在生産環境使用save指令。

方式二:bgsave指令

# 異步儲存資料集到磁盤上
> bgsave      
Redis持久化RDB&AOF
  • 當用戶端發服務發出bgsave指令時,Redis伺服器主程序會forks一個子程序來解決資料同步問題,在将資料儲存到rdb檔案之後,子程序會退出。
  • 是以,與save指令相比,Redis伺服器在處理bgsave采用子線程進行IO寫入,而主程序仍然可以接收其他請求,但forks子程序是同步的,是以forks子程序時,一樣不能接收其他請求,這意味着,如果forks一個子程序花費的時間太久(一般是很快的),bgsave指令仍然有阻塞其他客戶的請求的情況發生。
  • 我們可以控制單個Redis執行個體的最大記憶體,來盡可能降低Redis在fork時的事件消耗。以及上面提到的自動觸發的頻率減少fork次數,或者使用手動觸發,根據自己的機制來完成持久化。

方式三:通過配置檔案自動觸發

自動觸發的場景主要是有以下幾點:

  • 1.根據我們的 save m n 配置規則自動觸發;
  • 2.從節點全量複制時,主節點發送rdb檔案給從節點完成複制操作,主節點會觸發 bgsave;
  • 3.執行 debug reload 時;
  • 4.執行shutdown時,如果沒有開啟aof,也會觸發。

這裡我們講的是根據配置檔案自動觸發:

# 時間政策
#關閉RDB隻需要将所有的save儲存政策注釋掉即可
save 900 1   #900s内如果有1條資料寫入,就産生RDB快照
save 300 10 #300s内有10條資料寫入,就産生RDB快照 
save 60 10000  #60s内如果有10000條資料寫入,就産生RDB快照
# 檔案名稱
dbfilename dump.rdb
# 檔案儲存路徑
dir /var/lib/redis/6379
# 如果持久化出錯,主程序是否停止寫入
stop-writes-on-bgsave-error yes
# 是否壓縮
# 建議沒有必要開啟,畢竟Redis本身就屬于CPU密集型伺服器,再開啟壓縮會帶來更多的CPU消耗,相比硬碟成本,CPU更值錢。
rdbcompression no
# 導入時是否檢查
rdbchecksum yes      

save和bgsave對比
Redis持久化RDB&AOF
配置檔案自動生成rdb檔案背景使用的是bgsave方式。

RDB檔案

前面介紹了三種讓伺服器生成rdb檔案的方式,無論是由主程序生成還是子程序來生成,其過程如下:

  • 生成臨時rdb檔案,并寫入資料。
  • 完成資料寫入,用臨時檔案替代正式rdb檔案。
  • 删除原來的db檔案。

COW寫時複制(copy-on-write)

fork建立出的子程序,與父程序共享記憶體空間。也就是說,如果子程序不對記憶體空間進行寫入操作的話(Redis的子程序隻做資料落盤的操作,也不會去寫資料),記憶體空間中的資料并不會複制給子程序,這樣建立子程序的速度就很快了!(不用複制,直接引用父程序的實體空間,玩的是指針)。

Redis持久化RDB&AOF

當Redis父程序修改資料時,父程序會将原先的資料複制一份生成新的副本,然後修改父程序的指針,指向新的資料,此時父程序修改的新的資料不會影響到子程序。此時子程序的指針仍然指向舊的資料,子程序看到的資料還是bgsave時候的資料。當下一次執行bgsave時,新fork出來的子程序指針才會指向這次新的資料。

Redis持久化RDB&AOF

AOF(append-only file)

與RDB存儲某個時刻的快照不同,AOF持久化方式會記錄用戶端對伺服器的每一次寫操作指令,并将這些寫操作以追加的方式儲存到以字尾為aof檔案中,在Redis伺服器重新開機時,會加載并運作aof檔案的指令,以達到恢複資料的目的。

開啟AOF持久化的方式

方式一:bgrewriteaof指令

> bgrewriteaof      

方式二:通過配置檔案自動觸發

Redis預設不開啟AOF持久化方式,我們可以在配置檔案中開啟并進行更加詳細的配置:

#開啟aof
appendonly yes
# 檔案名稱
appendfilename "appendonly.aof"
# 同步方式
#appendfsync always #每次有新指令追加到 AOF 檔案時就執行一次 fsync ,非常慢,也非常安全。 
appendfsync everysec #預設方式,每秒 fsync 一次,足夠快,并且在故障時隻會丢失 1 秒鐘的資料。
#appendfsync no  #從不 fsync ,将資料交給作業系統來處理。更快,也更不安全的選擇。      

重寫

AOF将用戶端的每一個寫操作都追加到aof檔案末尾,比如對一個key多次執行incr指令,這時候,aof儲存每一次指令到aof檔案中,aof檔案會變得非常大。

127.0.0.1:6379> INCR readcount
(integer) 1
127.0.0.1:6379> INCR readcount
(integer) 2
127.0.0.1:6379> INCR readcount
(integer) 3
127.0.0.1:6379> INCR readcount
(integer) 4
127.0.0.1:6379> INCR readcount
(integer) 5      

這是一種resp協定格式資料,星号後面的數字代表指令有多少個參數,$号後面的數字代表這個參數有幾個字元

[root@redis 6379]# cat appendonly.aof
*2
$6
SELECT
$1
0
*2
$4
INCR
$9
readcount
*2
$4
INCR
$9
readcount
*2
$4
INCR
$9
readcount
*2
$4
INCR
$9
readcount
*2
$4
INCR
$9
readcount      

手動執行重寫指令BGREWRITEAOF:

127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started      

重寫後AOF檔案裡如下,将多個incr指令進行了合并:

[root@redis 6379]# cat appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
SET
$9
readcount
$1
5      

重寫配置參數

AOF重寫redis會fork出一個子程序去做(與bgsave指令類似),不會對redis正常指令處理有太多影響:

auto‐aof‐rewrite‐min‐size 64mb #aof檔案至少要達到64M才會自動重寫,檔案太小恢複速度本來就 很快,重寫的意義不大
auto‐aof‐rewrite‐percentage 100 #aof檔案自上一次重寫後檔案大小增長了100%則再次觸發重寫,例如上一次重寫的大小是64M,那麼下一次達到128M再做重寫      

AOF重寫流程圖
Redis持久化RDB&AOF

  • 在重寫期間,由于主程序依然在響應指令,為了保證最終備份的完整性;是以它依然會寫入舊的AOF file中,如果重寫失敗,能夠保證資料不丢失。
  • 為了把重寫期間響應的寫入資訊也寫入到新的檔案中,是以也會為子程序保留一個buf,防止新寫的file丢失資料。
  • 重寫是直接把目前記憶體的資料生成對應指令,并不需要讀取老的AOF檔案進行分析、指令合并。
  • 不管是RDB還是AOF都是先寫入一個臨時檔案,然後通過 rename 完成檔案的替換工作。

混合持久化

重新開機 Redis 時,我們很少使用 RDB來恢複記憶體狀态,因為會丢失大量資料。我們通常使用 AOF 日志重放,但是重放 AOF 日志性能相對 RDB來說要慢很多,這樣在 Redis 執行個體很大的情況下,啟動需要花費很長的時間。Redis 4.0 為了解決這個問題,帶來了一個新的持久化選項——混合持久化。通過如下配置可以開啟混合持久化(前提必須先開啟aof):

aof‐use‐rdb‐preambleyes #開啟混合持久化      

如果開啟了混合持久化,AOF在重寫時,不再是單純将記憶體資料轉換為RESP指令寫入AOF檔案,而是将重寫這一刻之前的記憶體做RDB快照處理,并且将RDB快照内容和增量的AOF修改記憶體資料的指令存在一起,都寫入新的AOF檔案,新的檔案一開始不叫appendonly.aof,等到重寫完新的AOF檔案才會進行改名,覆寫原有的AOF檔案,完成新舊兩個AOF檔案的替換。于是在 Redis 重新開機的時候,可以先加載 RDB 的内容,然後再重放增量 AOF 日志就可以完全替代之前的 AOF 全量檔案重放,是以重新開機效率大幅得到提升。

127.0.0.1:6379> set k 1
OK
127.0.0.1:6379> set k 2
OK
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started      

檢視此時的appendonly.aof檔案:此時存放的是RDB的内容

[root@redis 6379]# cat appendonly.aof
REDIS0009� redis-ver5.0.7�
�edis-bits�@�ctime�%y�_used-mem��
 aof-preamble���k� readcount�� R��i9$�[root@redis 6379]#      

如果新增加了資料:

127.0.0.1:6379> set k 3
OK      

那麼新的資料會以為RESP指令的方式追加在後面:

[root@redis 6379]# cat appendonly.aof
REDIS0009� redis-ver5.0.7�
�edis-bits�@�ctime�%y�_used-mem��
 aof-preamble���k� readcount�� R��i9$�*2
$6
SELECT
$1
0
*3
$3
set
$1
k
$1
3      

混合持久化AOF檔案結構如下:

Redis持久化RDB&AOF

從持久化中恢複資料

資料的備份、持久化做完了,我們如何從這些持久化檔案中恢複資料呢?如果一台伺服器上有既有RDB檔案,又有AOF檔案,該加載誰呢?

其實想要從這些檔案中恢複資料,隻需要重新啟動Redis即可。我們還是通過圖來了解這個流程:

Redis持久化RDB&AOF

啟動時會先檢查AOF檔案是否存在,如果不存在就嘗試加載RDB。那麼為什麼會優先加載AOF呢?因為AOF儲存的資料更完整,通過上面的分析我們知道AOF基本上最多損失1s的資料。

RBD和AOF對比

Redis持久化RDB&AOF

另外RBD不支援拉鍊,隻有一個dump.rdb檔案。

繼續閱讀