1. 程式人生 > >Redis學習之持久化機制

Redis學習之持久化機制

原文部落格地址: pjmike的部落格

前言

持久化就是將Redis記憶體中的資料寫入到磁碟中進行儲存,因為Redis是記憶體資料庫,資料都是存在記憶體中的,為了避免程序退出導致資料的丟失,所以需要將資料持久化到硬碟中,這樣下次Redis重啟後可以利用之前持久化的檔案實現資料恢復。

一般有兩種持久化方式:

  • 快照 : Redis RDB
  • 寫日誌: Redis AOF

下面對這兩種方式一一進行詳細闡述,關於更多Redis持久化深入介紹,可以拜讀 Redis持久化的經典之作——Redis persistence demystified

RDB

RDB 持久化是把當前程序資料生成快照儲存到硬碟的過程

,檔案格式是二進位制檔案,這種利用快照方式儲存資料,其實在很多領域都比較常見,比如雲伺服器備份資料,MySQL備份資料等等。

觸發RDB持久化過程一般分為兩種方式:

  • 手動觸發
  • 自動觸發

手動觸發

手動觸發又分別有兩種命令:

  • save命令:阻塞當前的Redis伺服器,直到RDB過程完成為止
  • bgsave命令(主流的觸發RDB持久化方式): Redis 程序執行 fork操作建立子程序,RDB 持久化由子程序負責,完成後自動結束,阻塞只發生在 fork 階段

save命令

127.0.0.1:6379> save
OK
複製程式碼

執行 save命令阻塞當前Redis,然後完成時返回一個 OK

bgsave

bgsave的執行流程如下圖(出自《Redis開發與運維》):

redis_bgsave

  • 執行 bgsave 命令,Redis 父程序 判斷當前是否存在正在執行的子程序,如 RDB/AOF子程序,如果存在 bgsave 命令直接返回
  • 父程序執行 fork 操作建立子程序,fork操作過程中父程序會阻塞,通過 info stats 命令 檢視 latest_fork_usec 選項,可以獲取最近一個 fork 操作的耗時,單位是 微秒
  • 父程序 fork 完成後,bgsave 命令 返回 Background saving started 資訊並不會阻塞父程序,可以繼續響應其他命令
  • 子程序建立 RDB 檔案,根據父程序記憶體生成臨時快照檔案,完成後對原有檔案進行原子替換
  • 程序傳送訊號給父程序表示完成,父程序更新統計資訊

自動觸發

自動觸發機制一般是在配置檔案中使用 save m n,表示 m 秒內資料集存在 n 次 修改時,自動觸發 bgsave,redis 預設的自動觸發機制如下:

# 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 900 1就表示當時間到 900s 時,如果Redis資料至少發生了一次修改,那麼就會執行 bgsave

RDB的相關配置

redis.conf有一系列關於 RDB的相關配置,如下所示:

# 快照的檔名
dbfilename dump.rdb

# 存放快照的目錄
dir ./

# 在進行快照備份時,是否進行壓縮。
# yes:壓縮,但是需要一些cpu的消耗。
# no:不壓縮,需要更多的磁碟空間。
rdbcompression yes

# 是否開啟RDB檔案的校驗,在寫入檔案和讀取檔案時都起作用,關閉時,寫入和啟動檔案有大約10%的效能提升,但無法檢查RDB的損壞情況
rdbchecksum yes

#自動觸發
#900秒後且至少1個key發生變化時建立快照  
save 900 1  
#300秒後且至少10個key發生變化時建立快照  
save 300 10  
#60秒後且至少10000個key發生變化時建立快照  
save 60 10000 
複製程式碼

一旦資料庫出現問題,那麼我們的RDB檔案中儲存的資料並不是全新的,從上次RDB檔案生成到Redis停機這段時間的資料全部丟掉了。例如,每隔5分鐘或者更長的時間來建立一次快照,Redis停止工作時(例如意外斷電)就可能丟失最近幾分鐘的資料。所以RDB 不適合實時持久化操作

其他機制

  • 全量複製: 如果從節點執行全量複製,主節點自動執行 bgsave 命令 生成 RDB 檔案併發送給從節點
  • debug reload: 重新載入redis會觸發 save操作
  • shutdown命令: 如果沒有開啟 AOF 持久化功能則自動執行 bgsave

AOF

AOF (append only file) 持久化: 以獨立日誌的方式記錄每次寫命令,重啟時再重新執行 AOF 檔案中的命令以達到恢復資料的目的,類似於 MySQL binlog。

與 RDB 相比,AOF 的實時性更好。

開啟AOF

redis.conf配置檔案中開啟 AOF持久化

# 是否開啟AOF,預設關閉(no)
appendonly yes

# AOF 檔名 (預設: "appendonly.aof")

appendfilename "appendonly.aof"

# 儲存路徑與 RDB 一樣,可配置

dir ./
複製程式碼

使用AOF流程:

  • 命令寫入(append): 所有的寫入命令會追加到 aof_buf 緩衝區中
  • 檔案同步(sync): AOF 緩衝區根據對應的策略向硬碟做同步操作(sync)
  • 檔案重寫(rewrite): 隨著AOF檔案越來越大,需要定期對AOF檔案進行重寫,達到壓縮的目的
  • 重啟載入(load): 當Redis重啟時,載入AOF檔案進行資料恢復

命令寫入

Redis先把命令追加到 aof_buf緩衝區中,該緩衝區是在系統的使用者態緩衝區中,更具體的講是在 Redis的緩衝記憶體中,緩衝記憶體主要包括: 客戶端緩衝,複製積壓緩衝區,AOF緩衝區。所以這裡Redis實際上是將命令追加到AOF緩衝區。

之所以先寫入緩衝區,是為了避免每次寫 AOF 檔案命令都直接寫入硬碟,導致硬碟IO成為Redis負載的瓶頸。

AOF 命令寫入的內容直接是文字協議格式,一種Redis制定的文字協議,詳情請查閱相關資料。它是一種純文字格式,具有很好的相容性,開啟AOF後,所有寫入命令都包含追加操作,直接採用 協議格式,避免了二次處理開銷。

檔案同步方式

檔案同步本質上將在使用者態緩衝區(具體說是AOF緩衝區)中的資料 通過System call 刷入到作業系統的核心態中,進入刷入硬碟中去。

其實涉及的兩個重要的系統呼叫(System Call):

  • write: 通過 write 系統呼叫,將資料寫入到核心緩衝區中後直接返回,後面的工作交由作業系統將核心緩衝區的資料寫入硬碟,這樣的好處是提高了IO效能
  • fsync:通過 fsync 系統呼叫 將資料提交到硬碟中,強制硬碟同步,將一直阻塞到寫入硬碟完成後返回

而檔案同步又有三種策略,可在 redis.conf配置檔案中進行配置:

  • appendfsync always: 單純靠呼叫 fsync將資料刷入到硬碟,是最有保證的完全的持久化,但速度也是最慢的,因為fsync存在阻塞,一般不推薦使用。
  • appendfsync everysec: 每隔一秒鐘,資料會通過write寫入到核心緩衝完成後返回。為了進一步保證持久化,又專門後臺開一個執行緒通過fsync將資料重新整理到磁碟,以避免核心緩衝內資料因系統故障宕機丟失。在效能和持久化方面做了很好的折中,是受推薦的方式。
  • appendfsync no: 通過write系統呼叫將資料寫入到核心快取,然後依賴OS的寫入,將資料從核心快取寫入到硬碟,一般為30秒左右一次。效能最好但是持久化最沒有保證,不被推薦,如果有系統宕機故障,最近30秒的資料有可能丟失

重寫機制

隨著命令不斷寫入AOF,檔案會越來越大,為了解決這個問題,Redis引入了AOF重寫機制壓縮檔案體積。 經過重寫,比如多條命令合併成一條命令等操作,然後重寫後的AOF檔案可以變小,以便更快被Redis載入

AOF重寫過程分為手動觸發和自動觸發:

  • 手動觸發:直接呼叫 bgrewriteaof命令
  • 自動觸發: 兩大引數
    • auto-aof-rewrite-min-size:表示執行 AOF重寫時檔案最小體積,預設為64MB
    • auto-aof-rewrite-percentage : AOF增長率,當前AOF檔案空間和上一次重寫後AOF檔案空間的比值

redis.conf配置檔案中,自動觸發引數設定如下:

#當AOF增長率為100%且達到了64mb時開始自動重寫AOF  
auto-aof-rewrite-percentage 100  
auto-aof-rewrite-min-size 64mb
複製程式碼

重新載入

Redis 持久化檔案載入流程如下,如果 RDB 與 AOF同時開啟,優先使用 AOF (下圖摘自《Redis開發與運維》):

redis_aof_reload

參考資料 & 鳴謝