Redis 持久化

black_monkey發表於2020-06-10

RDB

簡介

RDB持久化方式是通過快照(snapshotting)完成的,當符合一定條件時,redis會自動將記憶體中所有資料以二進位制方式生成一份副本並儲存在硬碟上。當redis重啟時,並且AOF持久化未開啟時,redis會讀取RDB持久化生成的二進位制檔案(預設名稱dump.rdb,可通過設定dbfilename修改)進行資料恢復,對於持久化資訊可以用過命令“info Persistence”檢視。

save

該命令會由worker thread 執行,因此會阻塞 redis 的 worker ,期間不會響應任何其他客戶端發來的請求,直到RDB快照檔案執行完畢,所以慎用。

測試

info persistence 
# rdb_last_save_time:1570126868
save
info persistence
# rdb_last_save_time:1570126928

bgsave

bgsave“後臺儲存”。與save 最大的差異為它並是由 worker thread 執行的,而是由redis fork 出子程式,交由子程式來完成持久化操作。

redis是在fork子程式這個時間段內 redis是阻塞的(此段時間不會響應客戶端請求),當子程式建立完成以後redis響應客戶端請求。

redis 不會再控制檯顯示完成資訊,但是會寫入日誌。

流程

客戶端執行bgsave命令,redis主程式收到指令並判斷此時是否在執行bgrewriteaof(AOF檔案重新過程,後續會講解),如果此時正好在執行則bgsave直接返回,不fork子程式,如果沒有執行bgrewriteaof重寫AOF檔案,則進入下一個階段;

主程式呼叫fork方法建立子程式,在建立子程式過程中redis主程式阻塞,所以不能響應客戶端請求;

子程式建立完成以後,bgsave命令返回Background saving started,此時標誌著redis可以響應客戶端請求了;

子經常根據主程式的記憶體副本建立臨時快照檔案,當快照檔案完成以後對原快照檔案進行替換;

子程式傳送訊號給redis主程式完成快照操作,主程式更新統計資訊(info Persistence可檢視),子程式退出;

測試

bgsave
Background saving started  # 子程式建立成功,它會去 完成持久化操作

檢視日誌

config get logfile
 11) "logfile"
 12) "/var/log/redis/redis-server.log"
cat "/var/log/redis/redis-server.log"
2497:M 04 Oct 2019 10:26:46.764 * Background saving started by pid 28960   # 開始後臺 持久化
2497:M 04 Oct 2020 10:26:46.772 * Background saving terminated with success   # 後臺持久化完成 

RDB相關配置

檢視配置的方法:

1 檢視配置檔案

2 在redis 中檢視當前 redis 的配置

CONFIG get *    # 獲取所有的配置
CONFIG get dir   # 獲取 快照檔案 儲存的 位置
CONFIG get dbfilename   # 獲取 快照檔案 的檔名

快照檔案位置

配置檔案中 dir 指定

快照檔名

配置檔案中 dbfilename

是否壓縮

配置檔案中 rdbcompression default:yes

設定儲存至本地資料庫時是否壓縮資料,預設為yes,採用LZF壓縮

yes 會耗費一定的CPU資源,預設是 yes 。

no 會使儲存的檔案變大(巨大)

是否校驗

配置檔案中 yesrdbchecksumy default: yes

yes 會消耗一部分CPU資源,但是資料相對安全不容易損壞

no 可以節約讀寫性過程約10%時間消耗,但是儲存一定的資料損壞風險

後臺持久化報錯

配置檔案中 stop-writes-on-bgsave-error default: yes

後臺儲存過程中如果出現錯誤執行緒,是否停止儲存操作,預設是停止的

no 則忽略錯誤繼續。

快照檢查

配置檔案中 rdbchecksum default: yes
在寫入檔案和讀取檔案時是否開啟rdb檔案檢查,檢查是否有無損壞,如果在啟動是檢查發現損壞,則停止啟動。

RDB觸發

自動觸發

配置檔案中 save default: yes

save second changes
# 檢視預設的配置
config get save
"900 1 300 10 60 10000"
# 900秒內 1次鍵更新了就觸發持久化 或 300秒內 10次更新 持久化 60 秒內 10000次更新 觸發持久化
# 該持久化是 bgsave

手動觸發

手動執行 savebgsave

其他觸發

以下幾種種情況下會觸發執行快照操作,並且預設的使用bgsave

主從複製時,從庫全量複製同步主庫資料,此時主庫會執行bgsave命令進行快照;

客戶端執行資料庫清空命令FLUSHALL時候,觸發快照;

客戶端執行shutdown關閉redis時,觸發快照,也可以 使用 nosave 引數顯式宣告不儲存快照

shutdown nosave

故障恢復

當redis意外崩潰或者關閉再次啟動時,此時AOF持久化未開啟時(預設未開啟),將使用RDB快照檔案恢復資料。

# 檢視日誌
cat /var/log/redis/redis-server.log
30448:M 04 Oct 2019 10:09:37.145 # Server initialized
30448:M 04 Oct 2019 10:09:37.145 * DB loaded from disk: 0.000 seconds   # 從快照恢復
30448:M 04 Oct 2019 10:09:37.146 * Ready to accept connections

缺點

RDB方式無論是執行指令還是利用配置,無法做到實時持久化,具體較大的可能性丟失資料

bgsave指令每次執行要執行fork操作建立子程式,要犧牲掉一些效能

Redis的眾多版本中未進行RDB檔案格式的版本統一,有可能出現個版本服務之間資料格式無法相容現象

儲存資料量較大,效率較低——基於快照思想,每次讀寫都是全部資料,當資料量巨大時,效率非常低
大資料量下的IO效能較低

AOF

簡介

日誌形式的AOF,將命令追加到檔案。AOF可以將Redis執行的每一條寫命令追加到磁碟檔案(appendonly.aof)中,在redis啟動時候優先選擇從AOF檔案恢復資料。因為要頻繁的將每一個操作記錄到檔案中,所以開啟AOF持久化會對效能有一定的影響,但是大部分情況下這個影響是可以接受的。

與RDB持久化相比,AOF持久化資料丟失更少,其消耗記憶體更少(RDB方式執行bgsve會有記憶體拷貝)。

AOF持久化過程

redisAOF持久化過程可分為以下階段:

追加寫入

redis將每一條寫命令以redis通訊協議新增至緩衝區aof_buf,這樣的好處在於在大量寫請求情況下,採用緩衝區暫存一部分命令隨後根據策略一次性寫入磁碟,這樣可以減少磁碟的I/O次數,提高效能。

同步三種策略

當寫命令寫入aof_buf緩衝區後,redis會將緩衝區的命令寫入到檔案,redis提供了三種同步策略,由配置引數appendfsync決定,下面是每個策略所對應的含義:

no

不使用fsync方法同步,而是交給作業系統write函式去執行同步操作,在linux作業系統中大約每30秒執行一次 sync(man 2 sync 檢視)。這種情況下,緩衝區資料同步不可控,並且在大量的寫操作下,aof_buf緩衝區會堆積會越來越嚴重,一旦redis出現故障,資料丟失嚴重,整體不可控。

always

表示每次有寫操作都呼叫fsync方法強制核心將資料寫入到aof檔案。這種情況下由於每次寫命令都寫到了檔案中, 雖然資料比較安全,但是因為每次寫操作都會同步到AOF檔案中,所以在效能上會有影響,同時由於頻繁的IO操作,硬碟的使用壽命會降低。

everysec

資料將使用呼叫作業系統write寫入檔案,並使用fsync每秒一次從核心重新整理到磁碟。 這是折中的方案,兼顧效能和資料安全,所以redis預設推薦使用該配置。

檔案重寫

當開啟AOF時,隨著時間推移,AOF檔案會越來越大,redis提出一種重寫的策略來緩解資料儲存和恢復壓力。

重寫策略

重複或無效的命令不寫入檔案

過期的資料不再寫入檔案

多條命令合併寫入(當多個命令能合併一條命令時候會對其優化合並作為一個命令寫入,例如“RPUSH list1 a RPUSH list1 b" 合併為“RPUSH list1 a b” )

觸發條件

AOF檔案觸發條件可分為手動觸發和自動觸發:

手動觸發:客戶端執行bgrewriteaof命令。

自動觸發:自動觸發通過以下兩個配置協作生效:

auto-aof-rewrite-min-size

AOF檔案最小重寫大小,只有當AOF檔案大小大於該值時候才可能重寫,4.0預設配置64mb。

auto-aof-rewrite-percentage

當前AOF檔案大小和最後一次重寫後的大小之間的比率等於或者等於指定的增長百分比,如100代表當前AOF檔案是上次重寫的兩倍時候才重寫。 

redis在AOF功能開啟的情況下,會維持以下三個變數

aof_current_size :記錄當前AOF檔案大小

aof_rewrite_base_size:記錄最後一次AOF重寫之後,AOF檔案大小

aof_rewrite_perc:增長百分比變數

每次當serverCron(伺服器週期性操作函式)函式執行時,它會檢查以下條件是否全部滿足,如果全部滿足的話,就觸發自動的AOF重寫操作:

沒有BGSAVE命令(RDB持久化)/AOF持久化在執行;

沒有BGREWRITEAOF在進行;

當前AOF檔案大小要大於server.aof_rewrite_min_size的值;

當前AOF檔案大小和最後一次重寫後的大小之間的比率等於或者大於指定的增長百分比(auto-aof-rewrite-percentage引數)

重寫過程

  AOF檔案重寫過程與RDB快照bgsave工作過程有點相似,都是通過fork子程式,由子程式完成相應的操作,同樣的在fork子程式簡短的時間內,redis是阻塞的,以下圖文說明其重寫過程:

開始bgrewriteaof,判斷當前有沒有bgsave命令(RDB持久化)/bgrewriteaof在執行,倘若有,則這些命令執行完成以後在執行。

主程式fork出子程式,在這一個短暫的時間內,redis是阻塞的。

當完成重寫後,將重寫後的aof 檔案合併到原有aof快取檔案中。並刪除臨時建立的重寫後的aof檔案

AOF實現本質

AOF實現本質是基於redis通訊協議,將命令以純文字的方式寫入到檔案中。

redis協議:

首先Redis是以行來劃分,每行以\r\n行結束。每一行都有一個訊息頭,訊息頭共分為5種分別如下:

(+) 表示一個正確的狀態資訊,具體資訊是當前行+後面的字元。

(-) 表示一個錯誤資訊,具體資訊是當前行-後面的字元。

(*) 表示訊息體總共有多少行,不包括當前行,*後面是具體的行數。

($) 表示下一行資料長度,不包括換行符長度\r\n,$後面則是對應的長度的資料。

(:) 表示返回一個數值,:後面是相應的數字節符。

我們可以直接檢視AOF檔案中的格式,如下圖:

資料恢復

之前已經提到當AOF開啟時候,redis資料恢復優先選用AOF進行資料恢復,以下使用停止redis來模擬redis故障,然後在重寫啟動進行恢復。

AOF配置引數

auto-aof-rewrite-min-size

AOF檔案最小重寫大小,只有當AOF檔案大小大於該值時候才可能重寫,4.0預設配置64mb。

auto-aof-rewrite-percentage

當前AOF檔案大小和最後一次重寫後的大小之間的比率等於或者等於指定的增長百分比,如100代表當前AOF檔案是上次重寫的兩倍時候才重寫。預設 100

appendfsync

上文中提到的三種策略,預設 everysec

always | everysec | no

aof-load-truncated yes

當redis突然執行崩潰時,會出現aof檔案被截斷的情況,Redis可以在發生這種情況時退出並載入錯誤,以下選項控制此行為。
如果aof-load-truncated設定為yes,則載入截斷的AOF檔案,Redis伺服器啟動發出日誌以通知使用者該事件。
如果該選項設定為no,則服務將中止並顯示錯誤並停止啟動。當該選項設定為no時,使用者需要在重啟之前使用redis-check-aof實用程式修復AOF檔案在進行啟動。

appendonly no

yes開啟AOF,no關閉AOF 預設 no

appendfilename

指定AOF檔名,4.0無法通過config set 設定,只能通過修改配置檔案設定。預設 appendonly.aof

RDB-AOF混合持久化

簡介

redis4.0新增了新的持久化方式混合持久化

混合持久化預設是關閉的,它採用一種rdb + aof 的方式來實現,檔案頭rdb 一個全量的快照,格式為二進位制,後面是 aof 格式。這樣恢復會先檢視開頭是否為REDIS,rdb開頭必然是REDIS。然後從快照恢復,之後從aof恢復。

這樣做的好處是可以結合 rdb 和 aof 的優點, 快速載入同時避免丟失過多的資料

缺點是 aof 裡面的 rdb 部分就是壓縮格式不再是 aof 格式,可讀性差。

開啟混合持久化

5 版本的redis 預設的開啟了aof-use-rdb-preamble 但是 appendonly 預設是 no 也就是說,只要開啟了aof 預設的會使用混合持久化。如果要使用單純的aof 則需要手動的 將 aof-use-rdb-preamble 設為 no (好坑)

4.0版本的混合持久化預設關閉的,通過aof-use-rdb-preamble配置引數控制,yes則表示開啟,no表示禁用,預設是禁用的,可通過config set修改。

混合持久化過程

建立子程式

生成全量的rdb快照,放在appendonly.aof 檔案頭部。然後,接下來將aof緩衝區的增量命令以aof方式寫入檔案尾

每次恢復資料時,首先從RDB部分恢復,然後執行aof。

資料恢復

開啟了混合持久化時,啟動redis依然優先載入aof檔案,aof檔案載入可能有兩種情況如下:

aof檔案開頭是rdb的格式, 先載入 rdb內容再載入剩餘的 aof。

aof檔案開頭不是rdb的格式,直接以aof格式載入整個檔案。

三種持久化方案對比

RDB

優點

RDB 是一個非常緊湊(compact)的檔案,體積小,傳輸速度快,適合災備。

RDB 可以最大化 Redis 的效能:父程式在儲存 RDB 檔案時唯一要做的就是 fork 出一個子程式,然後這個子程式就會處理接下來的所有儲存工作,父程式無須執行任何磁碟 I/O 操作。

RDB 在恢復大資料集時的速度比 AOF 的恢復速度要快很多。

缺點

RDB 丟資料將會丟掉兩次持久化之間的所有資料~

當redis中資料集比較大時候,RDB由於RDB方式需要對資料進行完成拷貝並生成快照檔案,fork的子程式會耗CPU,並且資料越大,RDB快照生成會越耗時。

RDB檔案是特定的格式,閱讀性差,由於格式固定,並且多版本之間存在不相容情況。很難受~

AOF

優點

資料更完整,秒級資料丟失(取決於設定fsync策略)

相容性較高,由於是基於redis通訊協議而形成的命令追加方式,無論何種版本的redis都相容,再者aof檔案是明文的,可閱讀性較好。

缺點

資料檔案體積較大,即使有重寫機制,但是在相同的資料集情況下,AOF檔案通常比RDB檔案大。

相對RDB方式,AOF速度慢於RDB,並且在資料量大時候,恢復速度AOF速度也是慢於RDB。

由於頻繁地將命令同步到檔案中,AOF持久化對效能的影響相對RDB較大,但是對於我們來說是可以接受的。

混合持久化

優點

混合持久化結合了RDB持久化 和 AOF 持久化的優點, 由於絕大部分都是RDB格式,載入速度快,同時結合AOF,增量的資料以AOF方式儲存了,資料更少的丟失。

缺點

由於前部分是RDB格式,閱讀性較差,相容性差,一旦開啟了混合持久化,4.0 版本之前的redis 都不認識這種aof檔案~ 。

相關文章