redis系列:RDB持久化與AOF持久化

前言

什麼是持久化?redis

持久化(Persistence),即把數據(如內存中的對象)保存到可永久保存的存儲設備中(如磁盤)。持久化的主要應用是將內存中的對象存儲在數據庫中,或者存儲在磁盤文件中、XML數據文件中等等。
持久化是將程序數據在持久狀態和瞬時狀態間轉換的機制。 ----摘自百度百科

Redis的數據都是存儲在內存中的,因此Redis持久化也就是要把Redis存儲在內存中的數據保存到硬盤。
Redis提供了兩種持久化方式數據庫

  1. RDB持久化(快照)
  2. AOF持久化(只追加操做的文件 Append-only file)

先來看看RDB持久化緩存

RDB持久化

RDB持久化是指在客戶端輸入savebgsave或者達到配置文件自動保存快照條件時,將Redis 在內存中的數據生成快照保存在名字爲 dump.rdb(文件名可修改)的二進制文件中。服務器

save命令

save命令會阻塞Redis服務器進程,直到RDB文件建立完畢爲止,在Redis服務器阻塞期間,服務器不能處理任何命令請求。
在客戶端輸入save網絡

192.168.17.101:6379> save
OK

服務端會出現下方字符app

1349:M 30 Jul 17:16:48.935 * DB saved on disk

bgsave命令

bgsave命令的工做原理以下函數

  1. 服務器進程pid爲1349派生出一個pid爲1357的子進程,
  2. 子進程將數據寫入到一個臨時 RDB 文件中
  3. 當子進程完成對新 RDB 文件的寫入時,Redis 用新 RDB 文件替換原來的 RDB 文件,並刪除舊的 RDB 文件。

在客戶端輸入bgsave性能

192.168.17.101:6379> bgsave
Background saving started

服務端會出現下方字符spa

1349:M 30 Jul 17:14:42.991 * Background saving started by pid 1357
1357:C 30 Jul 17:14:42.993 * DB saved on disk
1357:C 30 Jul 17:14:42.993 * RDB: 4 MB of memory used by copy-on-write
1349:M 30 Jul 17:14:43.066 * Background saving terminated with success
:bgsave命令執行期間
SAVE命令會被拒絕
不能同時執行兩個BGSAVE命令
不能同時執行BGREWRITEAOF和BGSAVE命令

自動保存

這個須要在配置文件redis.conf中修改,默認的保存策略以下操作系統

save 900 1    # 900 秒內有至少有 1 個鍵被改動
save 300 10   # 300 秒內有至少有 10 個鍵被改動
save 60 10000 # 60 秒內有至少有 1000 個鍵被改動

接下來看看RBD的配置有哪些

配置

################################ SNAPSHOTTING  ################################
# 觸發自動保存快照
# save <seconds> <changes>
# save <秒> <修改的次數>
save 900 1    
save 300 10   
save 60 10000 

# 設置在保存快照出錯時,是否中止redis命令的寫入
stop-writes-on-bgsave-error yes

# 是否在導出.rdb數據庫文件的時候採用LZF壓縮
rdbcompression yes

#  是否開啓CRC64校驗
rdbchecksum yes

# 導出數據庫的文件名稱
dbfilename dump.rdb

# 導出的數據庫所在的目錄
dir ./

優勢

  • RDB是一個很是緊湊(有壓縮)的文件,它保存了某個時間點的數據,很是適用於數據的備份。
  • RDB做爲一個很是緊湊(有壓縮)的文件,能夠很方便傳送到另外一個遠端數據中心 ,很是適用於災難恢復.
  • RDB在保存RDB文件時父進程惟一須要作的就是fork出一個子進程,接下來的工做所有由子進程來作,父進程不須要再作其餘IO操做,因此RDB持久化方式能夠最大化redis的性能.
  • 與AOF相比,在恢復大的數據集的時候,RDB方式會更快一些.
翻譯來自 http://www.redis.cn

缺點

  • Redis意外宕機 時,會丟失部分數據
  • 當Redis數據量比較大時,fork的過程是很是耗時的,fork子進程時是會阻塞的,在這期間Redis 是不能響應客戶端的請求的。

AOF持久化

AOF持久化是經過保存Redis服務器所執行的寫命令來記錄數據庫狀態,也就是每當 Redis 執行一個改變數據集的命令時(好比 SET), 這個命令就會被追加到 AOF 文件的末尾。

那麼咱們如何開啓AOF持久化功能呢?

開啓AOF持久化

修改redis.conf配置文件,默認是appendonly no(關閉狀態),將no改成yes便可

appendonly yes

在客戶端輸入以下命令也可,可是Redis服務器重啓後會失效

192.168.17.101:6379> config set appendonly yes
OK

接下來看看AOF持久化功能的實現

實現

AOF持久化功能的實現能夠分爲命令追加(append)、文件寫入和文件同步(sync)三個步驟。下面就是三個步驟的整個過程。

在Redis客戶端輸入以下命令

192.168.17.101:6379> set learnRedis testAOF
OK

appendonly.aof文件會增長以下內容

*2
$6
SELECT
$1
0
*3
$3
set
$10
learnRedis
$7
testAOF

命令追加

AOF持久化功能開啓時,服務器在執行完一個寫命令以後,會以協議格式將被執行的寫命令追加到服務器狀態的aof_buf緩衝區的末尾。此時緩衝區的記錄尚未寫入到appendonly.aof文件中。

文件的寫入和同步

爲何將文件寫入和文件同步合在一塊講呢?由於配置文件中提供了一個appendfsync參數,這個參數控制着文件寫入和同步的行爲。

關於文件的寫入和同步的資料以下

由於爲了提升文件的寫入效率,在現代操做系統中,當用戶調用write函數,將一些數據寫入到文件的時候,os一般會將寫入數據暫時保存在一個內存緩衝區裏面(例如,unix系統實如今內核中設有緩衝區高速緩存或頁高速緩存,當咱們向文件寫入數據時,內核一般先將數據複製到緩衝區中,而後排入隊列,晚些時候再寫入磁盤),這種方式稱爲延遲寫,等到緩衝區的空間被填滿,或者超過了指定的時限,或者內核須要重用緩衝區存放其它磁盤塊數據時,纔會真正將緩衝區中的全部數據寫入到磁盤裏面。

簡單來講就是

文件寫入:只是寫入到了內存緩衝區,可能尚未寫到文件所擁有的磁盤數據塊上
文件同步:將緩衝區中的內容沖洗到磁盤上

appendfsync參數

appendfsync選項的值 效果
always 每次有新命令時,就將緩衝區數據寫入並同步到 AOF 文件
everysec(默認) 每秒將緩衝區的數據寫入並同步到 AOF 文件
no 將緩衝區數據寫入AOF 文件,可是同步操做到交給操做系統來處理

載入與數據還原

讀取AOF文件並還原數據庫的步驟以下

  1. 建立一個不帶網絡鏈接的僞客戶端
  2. 從AOF文件中分析並讀取出一條寫命令
  3. 使用僞客戶端執行被讀出的寫命令
  4. 一直執行步驟二、3,知道AOF文件中的全部寫命令都被處理完畢爲止

圖片來自Redis設計與實現

這時可能會出現一個問題。服務器可能在程序正在對 AOF 文件進行寫入時停機,形成了 AOF 文件出錯,那麼 Redis 在重啓時會拒絕載入這個 AOF 文件,從而確保數據的一致性不會被破壞 當發生這種狀況時, 能夠用如下方法來修復出錯的 AOF 文件:

  • 爲現有的 AOF 文件建立一個備份。
  • 使用 Redis 附帶的 redis-check-aof 程序,對原來的 AOF 文件進行修復: redis-check-aof –fix
  • (可選)使用 diff -u 對比修復後的 AOF 文件和原始 AOF 文件的備份,查看兩個文件之間的不一樣之處。
  • 重啓 Redis 服務器,等待服務器載入修復後的 AOF 文件,並進行數據恢復。

另外redis.conf配置文件中還提供了一個參數來控制是否忽略最後一條可能存在問題的指令,以下

aof-load-truncated yes

重寫

因爲AOF 持久化是經過不斷地將命令追加到文件的末尾來記錄數據庫狀態的, 因此隨着寫入命令的不斷增長, AOF 文件的體積也會變得愈來愈大。 且有些命令是改變同一數據,是能夠合併成一條命令的。就比如對一個計數器調用了 100 次 INCR,AOF就會存入100 條記錄,其實存入一條數據就能夠了。

因此爲了處理這種狀況,Redis提供了AOF重寫機制。

AOF重寫機制的觸發有兩種機制,一個是經過調用命令BGREWRITEAOF

192.168.17.101:6379> BGREWRITEAOF
Background append only file rewriting started

另外一種是根據配置文件中的參數觸發,參數以下

auto-aof-rewrite-percentage 100 #當前AOF文件大小和上一次重寫時AOF文件大小的比值
auto-aof-rewrite-min-size 64mb  #文件的最小體積

服務端會出現以下信息

1349:M 30 Jul 17:19:25.311 * Background append only file rewriting started by pid 1392
1349:M 30 Jul 17:19:25.379 * AOF rewrite child asks to stop sending diffs.
1392:C 30 Jul 17:19:25.379 * Parent agreed to stop sending diffs. Finalizing AOF...
1392:C 30 Jul 17:19:25.380 * Concatenating 0.00 MB of AOF diff received from parent.
1392:C 30 Jul 17:19:25.380 * SYNC append only file rewrite performed
1392:C 30 Jul 17:19:25.381 * AOF rewrite: 4 MB of memory used by copy-on-write
1349:M 30 Jul 17:19:25.466 * Background AOF rewrite terminated with success
1349:M 30 Jul 17:19:25.467 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB)
1349:M 30 Jul 17:19:25.467 * Background AOF rewrite finished successfully

重寫步驟

  1. 建立子進程進行AOF重寫
  2. 將客戶端的寫命令追加到AOF重寫緩衝區
  3. 子進程完成AOF重寫工做後,會向父進程發送一個信號
  4. 父進程接收到信號後,將AOF重寫緩衝區的全部內容寫入到新AOF文件中
  5. 對新的AOF文件進行更名,原子的覆蓋現有的AOF文件

:AOF重寫不須要對現有的AOF文件進行任何讀取、分析和寫入操做。

配置

############################## APPEND ONLY MODE ###############################

# 是否開啓AOF功能
appendonly no

# AOF文件件名稱
appendfilename "appendonly.aof"

# 寫入AOF文件的三種方式
# appendfsync always
appendfsync everysec
# appendfsync no

# 重寫AOF時,是否繼續寫AOF文件
no-appendfsync-on-rewrite no

# 自動重寫AOF文件的條件
auto-aof-rewrite-percentage 100 #百分比
auto-aof-rewrite-min-size 64mb #大小

# 是否忽略最後一條可能存在問題的指令
aof-load-truncated yes

優勢

  • 使用AOF 會讓你的Redis更加持久化
  • AOF文件是一個只進行追加的日誌文件,不須要在寫入時讀取文件。
  • Redis 能夠在 AOF 文件體積變得過大時,自動地在後臺對 AOF 進行重寫 。
  • AOF文件可讀性高,分析容易

缺點

  • 對於相同的數據來講,AOF 文件大小一般要大於 RDB 文件
  • 根據所使用的 fsync 策略,AOF 的速度可能會慢於 RDB

數據載入

RDB和AOF都是在啓動時加載的,AOF開啓時,會優先從AOF文件從恢復數據 ,AOF關閉時纔會從RDB文件恢復數據。

注:不知從什麼版本開始,開啓AOF功能時AOF文件不存在也不會加載RDB文件了

相關文章
相關標籤/搜索