Redis學習之持久化機制
原文部落格地址: pjmike的部落格
前言
持久化就是將Redis記憶體中的資料寫入到磁碟中進行儲存,因為Redis是記憶體資料庫,資料都是存在記憶體中的,為了避免程序退出導致資料的丟失,所以需要將資料持久化到硬碟中,這樣下次Redis重啟後可以利用之前持久化的檔案實現資料恢復。
一般有兩種持久化方式:
- 快照 : Redis RDB
- 寫日誌: Redis AOF
下面對這兩種方式一一進行詳細闡述,關於更多Redis持久化深入介紹,可以拜讀 Redis持久化的經典之作——Redis persistence demystified
RDB
RDB 持久化是把當前程序資料生成快照儲存到硬碟的過程
觸發RDB持久化過程一般分為兩種方式:
- 手動觸發
- 自動觸發
手動觸發
手動觸發又分別有兩種命令:
- save命令:阻塞當前的Redis伺服器,直到RDB過程完成為止
- bgsave命令(主流的觸發RDB持久化方式): Redis 程序執行 fork操作建立子程序,RDB 持久化由子程序負責,完成後自動結束,阻塞只發生在 fork 階段
save命令
127.0.0.1:6379> save
OK
複製程式碼
執行 save
命令阻塞當前Redis,然後完成時返回一個 OK
bgsave
bgsave的執行流程如下圖(出自《Redis開發與運維》):
- 執行 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重寫時檔案最小體積,預設為64MBauto-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開發與運維》):