redis 持久化策略

有形无形發表於2024-10-17
一、redis持久化介紹
Redis是個基於記憶體的資料庫,服務一旦當機,記憶體中的資料將全部丟失。通常的解決方案是從資料庫來重新把這些資料寫進redis, 但後端資料庫有效能瓶頸,如果是大資料量的恢復,會對資料庫帶來巨大的壓力,導致程式響應慢。所以對Redis來說,實現資料的持久化, 避免從後端資料庫中恢復資料,是至關重要的。
redis 支援三種持久化方式:
1、RDB:Redis DataBase,RDB 持久化可以在指定的時間間隔內生成資料集的時間點快照(point-in-time snapshot),預設就是該方式。

2、AOF:Append Only File,AOF 持久化記錄伺服器執行的所有寫操作命令,並在伺服器啟動時,透過重新執行這些命令來還原資料集。
該方式預設關閉,需要手動開啟。如果RDB和AOF同時開啟,恢復資料時預設是使用AOF恢復資料,而不會使用RDB方式

3、RDB和AOF混合持久化(4.0之後才開始支援該方式),注意,這個不是簡單的把RDB和AOF同時開啟的意思,下面會介紹。

RDB和AOF優缺點:
RDB:

優點:資料壓縮、當機後資料恢復速度快
缺點:非實時備份,可能會導致資料丟失

AOF:
AOF類似於mysql的binlog,可以設定為每秒/每次/作業系統自動決定何時刷盤等模式,寫操作都以追加的形式,記錄到日誌裡。

優點:非常安全,根據刷盤策略不同最多丟失1s的資料(生產上一般不設定成作業系統自己決定刷盤的模式),並且日誌有可讀性
缺點:檔案較大,當機後資料恢復較慢

二、RDB持久化方式
觸發rdb持久化的方式有2種,分別是手動觸發和自動觸發。
2.1、手動觸發方式
手動觸發有兩種方式:save和bgsave命令

save命令:阻塞當前Redis伺服器讀寫操作,直到RDB過程完成為止,對於記憶體比較大的例項會造成長時間阻塞,不建議使用
bgsave命令:Redis程序執行fork操作建立子程序,RDB持久化過程由子程序負責,完成後自動結束。
當資料集非常大並且CPU效能不夠強大的話,Redis可能會阻塞客戶端幾毫秒甚至一秒

bgsave原理圖

具體流程如下:
1.redis客戶端執行bgsave命令或者自動觸發bgsave命令; 

2.主程序判斷當前是否已經存在正在執行的子程序,如果存在,那麼主程序直接返回; 

3.如果不存在正在執行的子程序,那麼就fork一個新的子程序進行持久化資料,fork過程是阻塞的,fork操作完成後主程序即可執行其他操作;

4.子程序先將資料寫入到臨時的rdb檔案中,待快照資料寫入完成後再原子替換舊的rdb檔案;

5.同時傳送訊號給主程序,通知主程序rdb持久化完成,主程序更新相關的統計資訊(info Persitence下的rdb_*相關選項)。
2.2、自動觸發方式
在以下幾種情況時會自動觸發

1.redis.conf中配置save m n,即在m秒內有n次修改時,自動觸發bgsave生成rdb檔案;
2.主從複製時,從節點要從主節點進行全量複製時也會觸發bgsave操作,生成當時的快照傳送到從節點;
3.執行debug reload命令重新載入redis時也會觸發bgsave操作;
4.預設情況下執行shutdown命令時,也會觸發bgsave操作,這裡要注意,關閉redis前要先備份老的rdb檔案,不然會被覆蓋;
5.執行flushdb、flushall命令是也會觸發bgsave操作,但此時生成的rdb檔案是空的

2.3、RDB持久化引數配置
# 指定在多長時間內,有多少次更新操作,就將資料同步到資料檔案(硬碟),可以多個條件配合
save 900 1
save 300 10
save 60 10000

# 設定持久化檔名,預設值為 dump.rdb,通常設定為 dump-埠號.rdb
dbfilename dump6379.rdb

# 設定讀寫檔案過程是否進行RDB格式校驗,預設 yes;若設定為 no,節約讀寫 10% 時間消耗,但存在資料損壞的風險
rdbchecksum yes

# 儲存資料時是否壓縮資料。預設是yes
rdbcompression yes

# 後臺持久化過程中如果出現錯誤現象,是否停止儲存操作,預設 yes
stop-writes-on-bgsave-error yes

# 指定檔案存放目錄
dir /opt/redis/data
三、AOF持久化
3.1、AOF持久化概述

快照功能並不是非常耐久(durable): 如果 Redis 因為某些原因而造成故障停機, 那麼伺服器將丟失最近寫入、且仍未儲存到快照中的那些資料。儘管對於某些程式來說, 資料的耐久性並不是最重要的考慮因素, 但是對於那些追求完全耐久能力(full durability)的程式來說, 快照功能就不太適用了。

從 1.1 版本開始, Redis 增加了一種完全耐久的持久化方式: AOF 持久化。

注意:redis和傳統資料庫的wal預寫日誌不同,redis是先寫資料,後寫AOF日誌。

3.2、AOF持久化原理
當AOF持久化功能開啟之後,伺服器在執行完一個寫命令之後,會以協議格式將被執行的寫命令追加到伺服器的 aof_buf 緩衝區,然後根據不同的策略再把緩衝區的資料同步(fsync)到磁碟AOF日誌檔案中。redis有三種不同的fsync策略: 1.no:作業系統自行決定何時刷盤 2.always:每次寫入一條命令都會立即被重新整理到磁碟 3.everysec:每秒進行一次 fsync 呼叫
3.3、AOF重寫機制
寫操作不斷執行的時候AOF檔案會越來越大。例如,如果你增加一個計數器100次,你的資料集裡只會有一個鍵儲存這最終值,但是卻有100條記錄在AOF中。其中99條記錄在重建當前狀態時是不需要的。

於是Redis支援一個有趣的特性:在後臺重建AOF而不影響服務客戶端。每當你傳送BGREWRITEAOF時,Redis將會寫入一個新的AOF檔案,包含重建當前記憶體中資料集所需的最短命令序列。如果你使用的是Redis 2.2的AOF,你需要不時的執行BGREWRITEAOF命令。Redis 2.4可以自動觸發日誌重寫,控制觸發自動重寫的引數為以下兩個:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

AOF重寫機制的流程
日誌重寫採用了和快照一樣的寫時複製機制。下面是過程:

1、Redis呼叫fork(),於是我們有了父子兩個程序。
2、子程序開始向一個臨時檔案中寫AOF。
3、父程序在一個記憶體緩衝區中積累新的變更(同時將新的變更寫入舊的AOF檔案,所以即使重寫失敗我們也安全)。
4、當子程序完成重寫檔案,父程序收到一個訊號,追加記憶體緩衝區到子程序建立的檔案末尾。
5、Redis原子性地重新命名舊檔案為新的,然後開始追加新資料到新檔案。
3.4、AOF引數配置
# 指定是否在每次寫操作後進行日誌記錄,也就是是否開啟AOF,預設為no 
appendonly yes

# 指定AOF日誌檔名
appendfilename "appendonly.aof"

# 指定寫AOF日誌的方式 ,共有3個可選值:
# everysec:每秒寫入一次,預設值
# no:表示由作業系統進行資料快取同步到磁碟 
# always:表示每次更新操作後都會自動呼叫fsync()將資料寫到磁碟(慢,安全) 
appendfsync always

# 此選項控制在進行 AOF 重寫(AOF rewrite)過程中是否執行同步操作(fsync),預設為no,表示進行fsync操作
# AOF 重寫是一個最佳化過程,它會生成一個新的、更緊湊的 AOF 檔案,以便減少 AOF 檔案的大小並提高效率。在重寫過程中,Redis 會繼續將新的寫操作追加到當前的 AOF 檔案中,同時在後臺建立一個新的 AOF 檔案
no-appendfsync-on-rewrite no

# 當 AOF 檔案大小超過上次重寫後 AOF 檔案大小的百分比時自動觸發,預設值為 100,也就是檔案大小翻了一倍後會觸發重寫(bgrewriteaof)
auto-aof-rewrite-percentage 100

# 當 AOF 檔案大小超過指定值時自動觸發,預設值為 64 MB
auto-aof-rewrite-min-size 64mb

# 指定資料庫存放目錄,注意如果是redis7之前,AOF的目錄和rdb的目錄是在一起的(都是用dir這個引數來配置),
# 如果是7.0之後的版本,redis把AOF檔案拆成了三個(7.0新特性Multi Part AOF,將單個 AOF 拆分為多個,該特性由阿里雲資料庫Tair團隊貢獻),
# 並且在這三個檔案之上會新建一層目錄(appendonlydir,這個目錄是redis自動建立,),三個檔案分別是appendonly.aof.1.base.rdb,appendonly.aof.1.incr.aof,appendonly.aof.manifest這個數字1每重寫一次就會加1
dir /opt/redis/data
3.4、AOF檔案出錯了怎麼辦
伺服器可能在程式正在對 AOF 檔案進行寫入時崩潰,如果是這樣那AOF記錄的資料就可能是不完整的, Redis在恢復資料時不會裝載已破壞的AOF檔案。當發生這種情況時, 可以用以下方法來修復出錯的 AOF 檔案:
# 使用 Redis 附帶的 redis-check-aof 程式,對原來的 AOF 檔案進行修復
redis-check-aof --fix AOF檔名
注意:--fix引數一定要帶上
四、AOF-RDB混合持久化方案
4.1、混合持久化概述
RDB 和 AOF 持久化各有利弊,RDB 可能會導致一定時間內的資料丟失,而 AOF 由於檔案較大則會影響 Redis 的啟動速度,為了能同時使用 RDB 和 AOF 各自的優點,Redis4.0之後新增了混合持久化的方式,但預設是關閉的,Redis 5.0之後預設是開啟的。
4.2、混合持久化原理
在 AOF 重寫之前,RDB 和 AOF 都是按照它們各自的持久化策略工作的(RDB和AOF模式都要開啟才行)。當 AOF 重寫被觸發時,混合持久化才開始發揮作用:當前的資料集會首先以RDB 格式寫入新 AOF 檔案的頂部,然後再追加新的命令到檔案的末尾,如下圖所示:

4.3、混合持久化開啟方式
首先RDB和AOF兩種持久化模式都要開啟
然後配置下面的引數:
aof-use-rdb-preamble yes

# 混合持久化的實現主要是靠主程序和子程序共同來完成的。

子程序進行AOF重寫:
首先建立新的AOF檔案 appendonly.rdb
將Redis當前的資料生成RDB快照寫入 appendonly.rdb 檔案的開始部分

主程序同時將新的寫操作命令寫入 AOF 重寫緩衝區 ,然後主程序將 AOF 重寫緩衝區的內容追加到 appendonly.rdb 檔案的 RDB 資料的末尾
最後使用重寫後的appendonly.rdb 檔案替換舊的 AOF 檔案

相關文章