四、Redis 持久化
- 四、Redis 持久化
- 4.1 持久化基本原理
- 4.2 RDB持久化
- 4.3 AOF持久化
- 4.4 RDB與AOF對比
- 4.5 持久化技術轉型
- 五、Redis 主從集群
- 六、Redis 分布式系統
- 七、Redis 緩存
- 八、Lua腳本詳解
- 九、分布式鎖
數據庫系列文章:
關系型數據庫:
- MySQL —— 基礎語法大全
- MySQL —— 進階
非關系型數據庫:
- Redis 的安裝與配置
- Redis 基本命令(上)
- Redis 基本命令(下)
四、Redis 持久化
????Redis是一個內存數據庫,所以其運行效率非常高。但也 存在一個問題:內存中的數據是不持久的,若 主機宕機 或 Redis 關機重啟,則內存中的數據全部丟失。當然,這是不允許的。 Redis 具有持久化功能,其會按照設置以 快照 或 操作日志 的形式將數據持久化到磁盤。
????根據持久化使用技術的不同,Redis 的持久化分為兩種: RDB
(Redis DataBase
) 與 AOF
(Append Only File
)。
4.1 持久化基本原理
????Redis 持久化 也稱為 鈍化, 是指將內存中數據庫的狀態描述信息保存到磁盤中。只不過是不同的持久化技術,對數據的狀態描述信息是不同的 ,生成的持久化文件也是不同的 。但它們的作用都是相同的:避免數據意外丟失。
????通過手動方式,或 自動定時方式,或 自動條件觸發方式,將內存中數據庫的狀態描述信息寫入到指定的持久化文件中。當系統重新啟動時,自動加載 持久化文件,并根據文件中數據庫狀態描述信息將數據恢復到內存中 ,這個數據恢復過程也稱為激活 。這個 鈍化 與 激活 的過程就是 Redis 持久化的基本原理。
????不過從以上分析可知, 對于 Redis 單機狀態下, 無論是手動方式,還是定時方式或條件觸發方式,都存在數據丟失問題: 在尚未手動自動保存時發生了 Redis 宕機狀況,那么從上次保存到宕機期間產生的數據就會丟失。不同的持久化方式,其數據的丟失率也是不同的。
????需要注意的是, RDB 是 默認持久化方式,但 Redis 允許 RDB 與 AOF 兩種持久化技術同時開啟,此時系統會使用 AOF 方式做持久化,即 AOF 持久化技術的 優先級要更高。同樣的道理,兩種技術同時開啟狀態下, 系統啟動時若兩種持久化文件同時存在,則 優先加載 AOF持久化文件。
4.2 RDB持久化
????RDB,Redis DataBase
,是指將內存中某一時刻的 數據快照 全量 寫入到指定的 rdb 文件
的持久化技術。 RDB 持久化默認是開啟的。 當 Redis 啟動時會 自動讀取 RDB 快照文件,將數據從硬盤載入到內存, 以恢復 Redis 關機前的數據庫狀態。
?? 4.2.1、持久化的執行
????RDB持久化的執行有三種方式:手動 save 命令
、手動 bgsave 命令
,與自動條件觸發
。
(1) 手動 save 命令
????通過在 redis-cli
客戶端中執行 save
命令可立即進行一次持久化保存。 save
命令在執行期間會 阻塞 redis-server
進程,直至持久化過程完畢。而在 redis-server
進程阻塞期間, Redis 不能處理任何讀寫請求,無法對外提供服務。
(2) 手動 bgsave 命令
????通過在 redis-cli
客戶端中執行 bgsave
命令可立即進行一次持久化保存。不同于 save
命令的是,正如該命令的名稱一樣, background save
,后臺運行 save
。 bgsave
命令會使服務器進程 redis-server
生成一個 子進程,由該子進程負責完成保存過程 。在子進程進行保存過程中,不會阻塞 redis-server
進程對客戶端讀寫請求的處理。
(3) 自動條件觸發
????自動條件觸發的本質仍是 bgsave
命令的執行。只不過是用戶通過在配置文件中做相應的設置后, Redis 會根據設置信息自動調用 bgsave
命令執行。具體配置方式,后面會詳解。
(4) 查看持久化時間
????通過 lastsave
命令可以查看最近一次執行持久化的時間 ,其返回的是一個 Unix
時間戳 (ms
)。
?? 4.2.2、RDB優化配置(重要 !!!)
????RDB 相關的配置在 redis.conf
文件的 SNAPSHOTTING
部分。
(1) save
該配置用于設置快照的自動保存觸發條件,即
save point
,保存點。該觸發條件是在指定時間段內發生了指定次數的寫操作。 除非另有規定,默認情況下持久化條件為save 3600 1 300 100 60 10000
。 其等價于以下三條:
save 3600 1
# 在 3600 秒 (1 小時) 內發生 1 次寫操作save 300 100
# 在 300 秒 (5 分鐘) 內發生 100 次寫操作save 60 10000
# 在 60 秒 (1 分鐘) 內發生 1 萬次寫操作如果不啟用RDB 持久化,只需設置
save
的參數為空串即可:save ""
。
(2) stop-write-on-bgsave-error
默認情況下,如果 RDB 快照已啟用(至少一個保存點),且最近的
bgsave
命令失敗, Redis將停止接受寫入。這樣設置是為了讓用戶意識到數據沒有正確地保存到磁盤上,否則很可能沒有人會注意到,并會發生一些災難 。當然,如果bgsave
命令后來可以正常工作了, Redis將自動允許再次寫入。
(3) rdbcompression
當進行持久化時啟用
LZF
壓縮字符串對象。雖然壓縮 RDB 文件會消耗系統資源,降低性能,但可大幅降低文件的大小,方便保存到磁盤,加速主從集群中從節點的數據同步。
(4) rdbchecksum
從 RDB5 開始, RDB 文件的 CRC64 校驗和就被放置在了文件末尾。這使格式更能 抵抗 RDB文件的損壞,但在保存和加載 RDB 文件時,性能會受到影響(約 10%),因此可以設置為
no
禁用校驗和以獲得最大性能。
- 在禁用校驗和的情況下創建的 RDB 文件的校驗和為零,這將告訴加載代碼跳過校驗檢查。
- 默認為
yes
,開啟了校驗功能。
(5) sanitize-dump-payload
該配置用于設置在加載 RDB 文件或進行持久化時是否開啟對
zipList
、listPack
等數據的全面安全檢測。該檢測可以降低命令處理時發生系統崩潰的可能。其可設置的值有三種選擇:
no
:不檢測yes
:總是檢測clients
:只有當客戶端連接時檢測。排除了加載 RDB 文件與進行持久化時的檢測。默認值本應該是
clients
,但其會影響 Redis 集群的工作,所以默認值為no
,不檢測。
(6) dbfilename
指定 RDB 文件的默認名稱,默認為
dump.rdb
。
(7) rdb-del-sync-files
主從復制時,==是否刪除==用于同步的從機上的 RDB 文件。默認是
no
,不刪除 。 不過需要注意, 只有當 從機 的 RDB 和 AOF 持久化功能 都未開啟 時才生效。
(8) dir
指定 RDB 與 AOF 文件的生成目錄。默認為 Redis 安裝根目錄。
?? 4.2.3、RDB文件結構
????RDB 持久化文件 dump.rdb
整體上有五部分構成:
(1) SOF
????SOF (Start Of File
) 是一個常量,一個字符串 REDIS
,僅包含這五個字符,其長度為 5 。用于標識 RDB文件的開始,以便在加載 RDB 文件時可以迅速判斷出文件是否是 RDB 文件。
(2) rdb_version
????這是一個整數,長度為 4 字節,表示 RDB 文件的版本號。
(3) EOF
????EOF (End Of File
) 是一個常量,占 1 個字節,用于標識 RDB 數據的結束,校驗和的開始。
(4) check_um
????校驗和 check_sum
用于判斷 RDB 文件中的內容是否出現 數據異常。 其采用的是 CRC64
校驗算法。
CRC校驗算法:
- 在持久化時,先將
SOF
、rdb_version
及內存數據庫中的數據快照
這三者的二進制數據拼接起來,形成一個二進制數(假設稱為數a
),然后再使用這個a
除以校驗和check_sum
,此時可獲取到一個余數b
,然后再將這個b
拼接到a
的后面,形成databases
。- 在加載時,需要先使用
check_sum
對 RDB 文件進行數據損壞驗證。
- 驗證過程:只需將 RDB 文件中除
EOF
與check_sum
外的數據除以check_sum
。只要除得的余數不是0
,就說明文件發生損壞。- 當然,如果余數是
0
,也不能肯定文件沒有損壞。這種驗證算法,是 數據損壞校驗,而不是數據沒有損壞的校驗。
(5) databases
???? databases
部分是 RDB 文件中最重要的數據部分,其可以包含任意多個非空數據庫。而每個 database
又是由三部分構成:
SODB
:是一個常量,占 1 個字節,用于標識一個數據庫的開始。db_number
:數據庫編號。key_value_pairs
:當前數據庫中的鍵值對數據。
???? 每個 key_value_pairs
又由很多個用于描述 鍵值對 的數據構成。
VALUE_TYPE
:是一個常量,占 1 個字節,用于標識該鍵值對中value
的類型。EXPIRETIME_UNIT
:是一個常量,占 1 個字節,用于標識 過期時間 的單位是秒
還是毫秒
。TIME
:當前key-value
的過期時間。
?? 4.2.4、RDB持久化過程 (面試的時候要說清楚過程)
???? 對于Redis 默認的 RDB 持久化,在進行 bgsave
持久化時, redis-server
進程會 fork
出一個 bgsave
子進程,由該子進程以 異步方式 負責完成持久化。而在持久化過程中, redis-server
進程不會阻塞,其會繼續接收并處理用戶的讀寫請求。
???? bgsave
子進程的詳細工作原理如下:
???? 由于子進程可以繼承 父進程的所有資源,且父進程不能拒絕子進程的繼承權。所以,bgsave
子 進程有權讀取到 redis-server
進程寫入到內存中的用戶數據,使得將內存數據持久化到 dump.rdb
成為可能。
???? bgsave
子進程 在持久化時首先會將內存中的全量數據 copy
到磁盤中的一個 RDB 臨時文件, copy
結束后,再將該文件 rename
為 dump.rdb
,替換掉原來的同名文件。
???? 不過,在進行持久化過程中,如果 redis-server
進程接收到了用戶寫請求,則系統會將內存中發生數據修改的物理塊 copy
出一個 副本。等內存中的全量數據 copy
結束后,會再將副本中的數據 copy
到 RDB 臨時文件。 這個副本的生成是由于 Linux 系統的 寫時復制技術(Copy-On-Write
)實現的。
寫時復制技術是Linux 系統的一種進程管理技術。
?????原本在
Unix
系統中,當一個主進程通過fork()
系統調用創建子進程后,內核進程 會 復制 主進程的整個內存空間中的數據,然后分配給子進程。這種方式存在的問題有以下幾點:
- 這個過程非常耗時
- 這個過程降低了系統性能
- 如果主進程修改了其內存數據,子進程副本中的數據是沒有修改的。即出現了數據冗余,而冗余數據最大的問題是數據一致性無法保證。
?????現代 的
Linux
則采用了更為有效的方 式:寫時復制。子進程會 繼承 父進程的所有資源,其中就包括主進程的內存空間。即子進程與父進程 共享內存 。只要內存被共享 ,那么該內存就是只讀的(寫保護的)。
????而 寫時復制 則是在任何一方需要寫入數據到共享內存時都會出現異常,此時內核進程就會將需要寫入的數據copy
出一個副本寫入到另外一塊非共享內存區域。
4.3 AOF持久化
????AOF,Append Only File
,是指 Redis 將每一次的 寫操作 都以 日志的形式 記錄到一個 AOF 文件中的持久化技術。當需要恢復內存數據時,將這些 寫操作重新執行一次,便會恢復到之前的內存數據狀態。
?? 4.3.1、AOF基礎配置
(1) AOF 的開啟
????默認情況下 AOF 持久化是沒有開啟的,通過修改配置文件中的 appendonly
屬性為 yes
可以開啟。
(2) 文件名配置
??Redis 7 在這里發生了重大變化。原來只有一個 appendonly.aof
文件,現在具有了三類多個文件:
- 基本文件:可以是
RDF
格式也可以是AOF
格式。其存放的內容是由RDB
轉為AOF
當時內存的快照數據。該文件可以有多個。 - 增量文件:以操作日志形式記錄轉為
AOF
后的寫入操作。該文件可以有多個。 - 清單文件:用于維護
AOF
文件的創建順序,保障激活時的應用順序。 該文件只有一個。
(3) 混合式持久化開啟
????對于基本文件可以是 RDF
格式也可以是 AOF
格式。通過 aof-use-rdb-preamble
屬性可以選擇。其默認值為 yes
,即默認 AOF
持久化的基本文件為 rdb
格式文件,也就是默認采用混合式持久化。
(4) AOF 文件目錄配置
????為了方便管理,可以專門為 AOF 持久化文件指定存放目錄。目錄名由 appenddirname
屬性指定,存放在 redis.conf
配置文件的 dir
屬性指定的目錄,默認為 Redis 安裝目錄。
?? 4.3.2、AOF文件格式
????AOF 文件包含三類文件:基本文件、增量文件 與 清單文件。其中基本文件一般為 rdb
格式,在前面已經研究過了。下面就來看一下 增量文件 與 清單文件 的內容格式。
(1) Redis 協議
????增量文件 擴展名為 .aof
,采用 AOF 格式。 AOF 格式其實就是 Redis 通訊協議格式, AOF持久化文件的 本質就是基于 Redis 通訊協議的文本 ,將命令以純文本的方式寫入到文件中。
????Redis 協議規定, Redis 文本是 以行來劃分 ,每行以 \r\n
行結束。每一行都有一個 消息頭 以表示消息類型。 消息頭 由六種不同的符號表示,其意義如下:
- (
+
) 表示一個正確的狀態信息 - (
-
) 表示一個錯誤信息 - (
*
) 表示消息體總共有多少行,不包括當前行 - (
$
) 表示下一行 消息數據 的長度,不包括換行符長度\r\n
- (
空
) 表示一個消息數據 - (
:
) 表示返回一個數值
(2) 查看AOF文件
????打開 appendonly.aof.1.incr.aof
文件,可以看到如下格式內容。
????以上內容中框起來的是三條命令。一條數據庫切換命令 SELECT 0
,兩條 set
命令。它們的意義如下:
(3) 清單文件
????打開清單文件 appendonly.aof.manifest
,查看其內容如下:
????該文件首先會按照 seq
序號列舉出所有基本文件,基本文件 type
類型為 b
,然后再按照 seq
序號再列舉出所有增量文件,增量文件 type
類型為 i
。
????對于 Redis 啟動時的數據恢復,也會按照該文件由上到下依次加載它們中的數據。
?? 4.3.3、Rewrite機制
????隨著使用時間的推移,AOF 文件會越來越大。為了防止 AOF 文件由于太大而占用大量的磁盤空間,降低性能, Redis 引入了 Rewrite
機制來對 AOF 文件進行壓縮。
(1) 何為 rewrite
????所謂 Rewrite
其實就是對 AOF 文件 進行重寫整理。當 Rewrite
開啟后,主進程 redis-server
創建出一個子進程 bgrewriteaof
,由該子進程完成 rewrite
過程。其首先對現有 aof
文件進行 rewrite
計算,將 計算結果 寫入到一個臨時文件,寫入完畢后,再 rename
該臨時文件為 原 aof
文件名,覆蓋原有文件。
(2) rewrite 計算
????rewrite
計算也稱為 rewrite 策略
。 rewrite 計算遵循以下策略:
- 讀操作命令 不寫入文件
- 無效命令 不寫入文件
- 過期數據 不寫入文件
- 多條命令 合并寫入 文件
(3) 手動開啟 rewrite
????Rewrite
過程的執行有兩種方式。一種是通過 bgrewriteaof
命令手動開啟,一種是通過設置條件自動開啟。
????以下是手動開啟方式:
????該命令會使主進程 redis-server
創建出一個子進程 bgrewriteaof
,由該子進程完成 rewrite
過程。而在 rewrite
期間, redis-server
仍是可以對外提供讀寫服務的。
(4) 自動開啟 rewrite
????手動方式需要人辦干預,所以一般采用自動方式。由于 Rewrite
過程是一個計算過程,需要消耗大量系統資源,會降低系統性能。所以, Rewrite
過程并不是隨時隨地任意開啟的,而是通過設置一些條件,當滿足條件后才會啟動,以降低對性能的影響。
????下面是配置文件中對于 Rewrite
自動啟動條件的設置。
auto-aof-rewrite-percentage
:開啟rewrite
的增大比例,默認100%
。指定為0
,表示 禁用自動rewrite
。auto-aof-rewrite-min-size
:開啟rewrite
的 AOF 文件最小值,默認 64M 。該值的設置主要是為了防止小 AOF 文件被rewrite
,從而導致性能下降。
????自動重寫 AOF 文件。當 AOF 日志文件大小增長到指定的百分比時, Redis 主進程 redis-server
會 fork
出一個子進程 bgrewriteaof
來完成 rewrite
過程。
????其工作原理如下:
- Redis 會記住最新
rewrite
后的 AOF 文件大小作為基本大小,如果從主機啟動后就沒有發生過重寫,則基本大小就使用啟動時 AOF 的大小。 - 如果當前AOF 文件 大于 基本大小的配置文件中指定的百分比閾值,且當前 AOF 文件 大于 配置文件中指定的最小閾值,則會觸發
rewrite
。
?? 4.3.4、AOF優化配置
(1) appendfsync
????當客戶端提交寫操作命令后,該命令就會寫入到 aof_buf
中,而 aof_buf
中的數據持久化到磁盤 AOF 文件的過程稱為數據同步。
????何時將 aof_buf
中的數據同步到 AOF 文件?采用不同的數據同步策略,同時的時機是不同的,有三種策略:
always
:寫操作命令寫入aof_buf
后會立即調用fsync()
系統函數,將其追加到 AOF 文件。該策略效率較低,但相對比較安全,不會丟失太多數據。最多就是剛剛執行過的寫操作在尚未同步時出現宕機或重啟,將這一操作丟失。no
:寫操作命令寫入aof_buf
后什么也不做,不會調用fsync()
函數。而將aof_buf
中的數據同步磁盤的操作由操作系統負責。 Linux 系統默認同步周期為 30 秒。效率較高。everysec
:默認策略。寫操作命令寫入aof_buf
后并不直接調用fsync()
,而是 每秒調用一次fsync()
系統函數來完成同步。該策略兼顧到了性能與安全,是一種折中方案。
(2) no-appendfsync-on-rewrite
????該屬性用于指定, 當 AOF fsync
策略設置為 always
或 everysec
當主進程創建了子進程 正在執行 bgsave
或 bgrewriteaof
時, 主進程是否不調用 fsync()
來做數據同步。設置為 no
,雙重否定即肯定,主進程會調用 fsync()
做同步。而 yes
則不會調用 fsync()
做數據同步。
????如果調用 fsync()
,在需要同步的數據量非常大時,會==阻塞主進程==對外提供服務,即會存在延遲問題。如果不調用 fsync()
,則 AOF fsync
策略相當于設置為了 no
,可能會 存在 30 秒數據丟失的風險。
(3) aof-rewrite-incremental-fsync
????當 bgrewriteaof
在執行過程也是先將 rewrite
計算的結果寫入到了 aof_rewr ite_buf
緩存中,然后當緩存中數據達到一定量后就會調用 fsync()
進行 刷盤操作,即 數據同步 ,將數據寫入到 臨時文件。 該屬性用于控制 fsync()
每次刷盤的數據量最大不超過 4MB 。這樣可以避免由于單次刷盤量過大而引發長時間阻塞。
(4) aof-load-turncated
????在進行 AOF 持久化過程中可能會出現 系統突然宕機的情況,此時寫入到 AOF 文件中的最后一條數據可能會不完整。當主機啟動后, Redis 在 AOF 文件不完整的情況下是否可以啟動,取決于屬性 aof-load-truncated
的設置。其值為:
yes
: AOF 文件最后不完整的數據直接從 AOF 文件中截斷刪除,不影響 Redis 的啟動。no
:AOF 文件最后不完整的數據不可以被截斷刪除, Redis 無法啟動。
(5) aof-timestamp-enabled
????該屬性設置為 yes
則會開啟在 AOF 文件中增加時間戳的顯示功能,可方便按照時間對數據進行恢復。但該方式可能會與 AOF 解析器不兼容,所以默認值為 no
,不開啟。
?? 4.3.5、AOF持久化過程
AOF 詳細的持久化過程如下:
- Redis 接收到的 寫操作命令 并不是直接追加到磁盤的 AOF 文件的,而是將每一條寫命令 按照 redis 通訊協議格式 暫時 添加到 AOF 緩沖區
aof_buf
。 - 根據設置的數據同步策略,當同步條件滿足時,再將緩沖區中的數據 一次性寫入磁盤的 AOF 文件,以減少磁盤 IO 次數,提高性能。
- 當磁盤的 AOF 文件大小達到了
rewrite
條件時,redis-server
主進程會fork
出一個子進程bgrewriteaof
,由該子進程完成rewrite
過程。 - 子進程
bgrewriteaof
首先對該磁盤 AOF 文件進行rewrite
計算,將計算結果寫入到一個臨時文件,全部寫入完畢后,再rename
該臨時文件為磁盤文件的原名稱,覆蓋原文件。 - 如果在
rewrite
過程中又有寫操作命令追加,那么這些數據會暫時寫入aof_rewrite_buf
緩沖區。等將全部rewrite
計算結果寫入臨時文件后,會先將aof_rewrite_buf
緩沖區中的數據寫入臨時文件,然后再rename
為磁盤文件的原名稱,覆蓋原文件。
4.4 RDB與AOF對比
?? 4.4.1、RDB優勢與不足
(1)RDB優勢
- RDB 文件較小
- 數據恢復較快
(2)RDB不足
- 數據安全性較差
- 寫時復制會降低性能
- RDB 文件可讀性較差
?? 4.4.2、AOF優勢與不足
(1)AOF優勢
- 數據安全性高
- AOF 文件可讀性強
(2)AOF不足
- AOF 文件較大
- 寫操作會影響性能
- 數據恢復較慢
4.5 持久化技術轉型
- 官方推薦使用
RDB
與AOF
混合式持久化。 - 若對數據安全性要求不高,則推薦使用 純
RDB
持久化方式。 - 不推薦使用純
AOF
持久化方式。 - 若 Redis 僅用于緩存,則無需使用任何持久化技術。
🚀🚀🚀 Redis 持久化 快速食用:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------->