超詳細!徹底說明白Redis持久化
Redis作為一款被廣泛應用的內存數據庫,想必大家都用過,而作為內存數據庫,其持久化機制是確保數據安全和穩(wěn)定性的關鍵所在。
想象一下,當你的應用突然斷電或服務器發(fā)生故障時,如果沒有持久化,那些寶貴的數據就可能瞬間消失,那么這樣的數據庫誰還會去使用呢?
因此,了解Redis持久化的原理,對于Redis保障數據的完整性是至關重要的,這也是為什么面試中經常會涉及到Redis持久化的問題。
這篇文章就跟各位一起來學習下Redis的持久化機制。
Redis持久化方式
Redis持久化有兩種方式:RDB(Redis DataBase)和AOF(Append Only File)。
圖片
RDB:RDB文件是一個經過壓縮的二進制文件。
AOF:AOF則是以追加的方式記錄Redis執(zhí)行的每一條寫命令。
RDB 和 AOF 是可以同時開啟的,在這種情況下,當Redis重啟的時候會優(yōu)先載入 AOF 文件來恢復原始的數據。
接下來,我會分別介紹 RDB 和 AOF 的實現原理。
RDB
RDB 是 Redis 默認的持久化方式(AOF默認是關閉的),它將 Redis 在內存中的數據寫入到硬盤中,生成一個快照文件。
快照文件是一個二進制文件,包含了 Redis 在某個時間點內的所有數據。
RDB的優(yōu)點是快速、簡單,適用于大規(guī)模數據備份和恢復。
但是,RDB也有缺點,例如數據可能會丟失,因為 Redis 只會在指定的時間點生成快照文件。如果在快照文件生成之后,但在下一次快照文件生成之前服務器宕機,那么這期間的數據就會丟失。
如下圖,T2 時刻如果服務器宕機,則 k3 和 k4 鍵的數據可能會丟失。
圖片
由于 RDB 文件是以二進制格式保存的,因此它非常緊湊,并且在 Redis 重啟時可以迅速地加載數據。相比于AOF,RDB文件一般會更小。
RDB 持久化觸發(fā)有兩種方式:自動 和 手動。
手動:手動方式通過 save 命令或 bgsave 命令進行。
自動:自動方式則是在配置文件中設置,滿足條件時自動觸發(fā)。
圖片
手動方式
- save:save 命令會阻塞 Redis 服務器進程,直到 RDB 文件創(chuàng)建完畢為止,在服務器進程阻塞期間,服務器不能處理任何命令請求。
- bgsave:bgsave 命令會 fork 一個子進程(注意是子進程,不是子線程)在后臺生成快照文件,不會阻塞 Redis 服務器,服務器進程(父進程)可以繼續(xù)處理命令請求。
bgsave命令執(zhí)行期間,客戶端發(fā)送的 save 和 bgsave 命令會被拒絕,這樣的目的是為了防止父進程和子進程之間產生競爭。
自動方式
自動方式是指通過服務器配置文件的 save 選項,來讓 Redis 每隔一段時間自動執(zhí)行 bgsave ,本質上還是通過 bgsave 命令去實現。
配置文件的 save 選項允許配置多個條件,只要其中任何一個條件滿足,就會觸發(fā) bgsave。
即:"N 秒內數據集至少有 M 個改動" 這一條件被滿足時。
舉個例子,如果我們向服務器提供以下配置:
save 900 1
save 300 10
save 60 10000
那么只要滿足以下三個條件中的任意一個,bgsave 命令就會被執(zhí)行:
- 服務器在 900秒 之內,對數據庫進行了至少 1次 修改。
- 服務器在 300秒 之內,對數據庫進行了至少 10次 修改。
- 服務器在 60秒 之內,對數據庫進行了至少 10000次 修改。
如果用戶沒有主動設置 save 選項,那么服務器會為 save 選項設置默認條件:
save 900 1
save 300 10
save 60 0000
知道上面這些之后我們還要解決兩個問題:
- save 選項配置,Redis是通過什么來判斷的?
- Redis 判斷的時機是什么時候?
問題一:save 選項配置,Redis是通過什么來判斷的?
Redis 服務器內部維護了一個計數器:dirty 和一個時間戳:lastsave。
- dirty計數器:dirty計數器記錄距離上一次成功執(zhí)行 save 命令或者 bgsave 命令之后,服務器對數據庫狀態(tài)(服務器中的所有數據庫)進行了多少次修改(包括寫入、刪除、更新等操作),命令修改了多少次數據庫,dirty計數器的值就增加多少。
- lastsave時間戳:lastsave時間戳則記錄了服務器上一次成功執(zhí)行 save 命令或者 bgsave 命令的時間。
舉個例子,某一時刻,dirty 計數器和 lastsave 時間戳的值如下:
dirty:200
lastsave:1703952000000
表示服務器在上次保存之后(2023-12-31 00:00:00),對數據庫狀態(tài)共進行了 200 次修改。
通過這種方式來判斷條件是否滿足。
問題二:Redis 判斷的時機是什么時候?
Redis通過周期性操作函數 serverCron 默認每隔100毫秒就會執(zhí)行一次檢查,來判斷 save 選項所設置的保存條件是否已經滿足。
serverCron 會遍歷所有保存條件,只要有任意一個條件被滿足,就執(zhí)行 bgsave 命令。
bgsave 執(zhí)行完成之后,Redis會重置 dirty 和 lastsave 的值。dirty 重置為0,lastsave 更新為上次 bgsave 的時間。
fork 函數與寫時復制
在 Redis 中,bgsave命令使用 fork 函數創(chuàng)建子進程生成RDB時,允許父進程接收和處理寫命令。
那 Redis 是如何實現 一邊處理寫請求,同時生成RDB文件的呢?
Redis 使用操作系統(tǒng)的 寫時復制技術 COW(Copy On Write) 來實現快照的持久化。
Redis 的使用場景中通常有大量的讀操作和較少的寫操作,而 fork 函數可以利用 Linux 操作系統(tǒng)的寫時復制(Copy On Write,即 COW)機制,讓父子進程共享內存,從而減少內存占用,并且避免了沒有必要的數據復制。
隨帶一提:JDK的 CopyOnWriteArrayList 和 CopyOnWriteArraySet 容器也使用到了寫時復制技術。
我們可以使用 Linux下的 man fork 命令來查看下 fork 函數的說明文檔。
圖片
翻譯如下:
在Linux下,fork()是使用寫時復制的頁實現的,所以它唯一的代價是復制父進程的頁表以及為子進程創(chuàng)建獨特的任務結構所需的時間和內存。
簡單來說就是 fork()函數會復制父進程的地址空間到子進程中,復制的是指針,而不是數據,所以速度很快。
當沒有發(fā)生寫的時候,子進程和父進程指向地址是一樣的,父子進程共享內存空間,這時可以將父子進程想象成一個連體嬰兒,共享身體。
直到發(fā)生寫的時候,系統(tǒng)才會真正拷貝出一塊新的內存區(qū)域,讀操作和寫操作在不同的內存空間,子進程所見到的最初資源仍然保持不變,從而實現父子進程隔離。
此做法的主要優(yōu)點是如果期間沒有寫操作,就不會有副本被創(chuàng)建。
示意圖如下:
圖片
通過使用 fork 函數和寫時復制機制,Redis 可以高效地執(zhí)行 RDB 持久化操作,并且不會對 Redis 運行過程中的性能造成太大的影響。
同時,這種方式也提供了一種簡單有效的機制來保護 Redis 數據的一致性和可靠性。
不過,fork函數有兩點注意:
- fork 的這個過程主進程是阻塞的,fork 完之后不阻塞。
- 當數據集比較大的時候,fork 的過程是非常耗時的,過程可能會持續(xù)數秒,可能會因為數據量大而導致主進程長時間被掛起,造成Redis服務不可用。
RDB 相關配置
以下是一些 RDB 的相關參數配置:
- save:指定 RDB 持久化操作的條件。當 Redis 的數據發(fā)生變化,并且經過指定的時間(seconds)和變化次數(changes)后,Redis 會自動執(zhí)行一次 RDB 操作。例如,save 3600 10000 表示如果 Redis 的數據在一個小時內發(fā)生了至少 10000 次修改,那么 Redis 將執(zhí)行一次 RDB 操作。
- stop-writes-on-bgsave-error:指定在 RDB 持久化過程中如果出現錯誤是否停止寫入操作。如果設置為 yes,當 Redis 在執(zhí)行 RDB 操作時遇到錯誤時,Redis 將停止接受寫入操作;如果設置為 no,Redis 將繼續(xù)接受寫入操作。
- rdbcompression:指定是否對 RDB 文件進行壓縮。如果設置為 yes,Redis 會在生成 RDB 文件時對其進行壓縮,從而減少磁盤占用空間;如果設置為 no,Redis 不會對生成的 RDB 文件進行壓縮。
- rdbchecksum:指定是否對 RDB 文件進行校驗和計算。如果設置為 yes,在保存 RDB 文件時,Redis 會計算一個 CRC64 校驗和并將其追加到 RDB 文件的末尾;在加載 RDB 文件時,Redis 會對文件進行校驗和驗證,以確保文件沒有受到損壞或篡改。
- replica-serve-stale-data:這是 Redis 4.0 中新增的一個配置項,用于指定復制節(jié)點在與主節(jié)點斷開連接后是否繼續(xù)向客戶端提舊數據。當設置為 yes 時,在復制節(jié)點與主節(jié)點斷開連接后,該節(jié)點將繼續(xù)向客戶端提供舊數據,直到重新連接上主節(jié)點并且同步完全新的數據為止;當設置為 no 時,復制節(jié)點會立即停止向客戶端提供數據,并且等待重新連接上主節(jié)點并同步數據。需要注意的是,當 replica-serve-stale-data 設置為 yes 時,可能會存在一定的數據不一致性問題,因此建議僅在特定場景下使用。
- repl-diskless-sync:這是 Redis 2.8 中引入的一個配置項,用于指定復制節(jié)點在進行初次全量同步(即從主節(jié)點獲取全部數據)時是否采用無盤同步方式。當設置為 yes 時,復制節(jié)點將通過網絡直接獲取主節(jié)點的數據,并且不會將數據存儲到本地磁盤中;當設置為 no 時,復制節(jié)點將先將主節(jié)點的數據保存到本地磁盤中,然后再進行同步操作。采用無盤同步方式可以避免磁盤 IO 操作對系統(tǒng)性能的影響,但同時也會增加網絡負載和內存占用。
AOF
AOF 持久化是按照 Redis 的寫命令順序將寫命令追加到磁盤文件的末尾,是一種基于日志的持久化方式,它保存了 Redis 服務器所有寫入操作的日志記錄。
AOF 的核心思想是將 Redis 服務器執(zhí)行的所有寫命令追加到一個文件中。當Redis服務器重新啟動時,可以通過重新執(zhí)行 AOF 中的命令來恢復服務器的狀態(tài)。
圖片
AOF 文件解讀
一個簡單的 AOF 文件示例如下:
圖片
這個文件展示了兩條命令:
select 0
set k1 hello
其中:
- *號:表示參數個數,后面緊跟著參數的長度和值。
- $號:表示參數長度,后面緊跟著參數的值。
AOF文件中保存的所有命令都遵循相同的格式,即以*開頭表示參數個數,$開頭表示參數長度,其后緊跟著參數的值。
AOF有個比較好的優(yōu)勢是可以恢復誤操作
舉個例子,如果你不小心執(zhí)行了 FLUSHALL 命令,導致數據被誤刪了 ,但只要 AOF 文件未被重寫,那么只要停止服務器,移除 AOF 文件末尾的 FLUSHALL 命令,并重啟 Redis ,就可以將數據集恢復到 FLUSHALL 執(zhí)行之前的狀態(tài)。
AOF 的寫入與同步
當啟用 AOF 時,Redis 發(fā)生寫命令時其實并不是直接寫入到AOF 文件,而是將寫命令追加到AOF緩沖區(qū)的末尾,之后 AOF緩存區(qū)再同步至 AOF文件中。
圖片
這行為其實不難理解,Redis 寫入命令十分頻繁,而 AOF 文件又位于磁盤上,如果每次發(fā)生寫命令就要操作一次磁盤,性能就會大打折扣。
而 AOF 緩存區(qū)同步至 AOF 文件,這一過程由名為 flushAppendonlyFile 的函數完成。
而 flushAppendOnlyFile 函數的行為由服務器配置文件的 appendfsync 選項來決定,該參數有以下三個選項:
- always:每次發(fā)生寫命令,都同步到 AOF 文件,是最安全的選項。
- everysec:每秒鐘同步寫入一次到 AOF 文件,在性能和安全之間做了一個平衡。
- no:不主動寫入 AOF 文件,何時同步由操作系統(tǒng)來決定。
默認情況下,Redis的 appendfsync 參數為 everysec 。如果需要提高持久化安全性,可以將其改為 always ,如果更關注性能,則可以將其改為 no。但是需要注意的是,使用 no 可能會導致數據丟失的風險,建議在應用場景允許的情況下謹慎使用。
AOF 重寫
上面我們講了 AOF 是通過追加命令的方式去記錄數據庫狀態(tài)的,那么當隨著服務器運行時間的流逝,AOF 文件可能會越來越大,達到幾G甚至幾十個G。
過大的 AOF 文件會對 Redis 服務器甚至宿主機造成影響,并且 AOF 越大,使用 AOF 來進行數據恢復所需的時間也就越多。
為了解決 AOF 文件體積膨脹的問題,Redis 提供了 AOF 文件重寫(rewrite)機制。
Redis的 AOF 重寫機制指的是將 AOF 文件中的冗余命令刪除,以減小 AOF 文件的大小并提高讀寫性能的過程。
通過該功能,Redis 服務器可以創(chuàng)建一個新的 AOF 文件來替代現有的 AOF 文件,新舊兩個 AOF 文件所保存的數據庫狀態(tài)相同,但新 AOF 文件不會包含任何浪費空間的冗余命令,所以新 AOF 文件的體積通常會比舊 AOF 文件的體積要小得多。
AOF重寫的實現
雖然叫做AOF重寫,但實際上,AOF 文件重寫并不需要對現有的AOF 文件進行任何讀取、分析或者寫入操作。
AOF重寫是通過讀取服務器當前的數據庫狀態(tài)來實現的。
我舉個例子大家就明白了,假設我對 Redis 執(zhí)行了下面六條命令:
rpush list "A"
rpush list "B"
rpush list "C"
rpush list "D"
rpush list "E"
rpush list "F"
那么服務器為了保存當前 list鍵 的狀態(tài),會在AOF文件中寫入上述六條命令。
而我現在要對 AOF 進行重寫的話,其實最高效最簡單的方式不是挨個讀取和分析現有AOF文件中的這六條命令。
而是直接從數據庫中讀取鍵 list 的值,然后用一條命令:rpush list "A" "B" "C" "D" "E" "F",可以直接代替原 AOF 文件中的六條命令。
命令由六條減少為一條,重寫的目的就達到了。
Redis的AOF重寫機制采用了類似于復制的方式,首先將內存中的數據快照保存到一個臨時文件中,然后遍歷這個臨時文件,只保留最終狀態(tài)的命令,生成新的AOF文件。
具體來說,Redis執(zhí)行AOF重寫可以分為以下幾個步驟:
- 開始AOF重寫過程,向客戶端返回一個提示信息。
- 創(chuàng)建一個臨時文件,并將當前數據庫中的鍵值對寫入到臨時文件中。
- 在創(chuàng)建的臨時文件中將所有的寫命令都轉換成Redis內部的表示格式,即使用一系列的Redis命令來表示一個操作,例如使用SET命令來表示對某個鍵進行賦值操作。
- 對臨時文件進行壓縮,去掉多余的空格和換行符等,減小文件體積。
- 將壓縮后的內容寫入到新的AOF文件中。
- 停止寫入命令到舊的AOF文件,并將新的AOF文件的文件名替換為舊的AOF文件的文件名。
- 結束AOF重寫過程,并向客戶端發(fā)送完成提示信息。
Redis提供了手動觸發(fā)AOF重寫的命令 BGREWRITEAOF ,重寫過程是由父進程 fork 出來的子進程來完成的,期間父進程可以繼續(xù)處理請求。
可以在Redis的客戶端中執(zhí)行該命令來啟動AOF重寫過程。Redis 2.2 需要自己手動執(zhí)行 BGREWRITEAOF 命令,到了 Redis 2.4 則可以自動觸發(fā) AOF 重寫。
具體操作步驟如下:
- 打開redis-cli命令行工具,連接到Redis服務。
- 執(zhí)行BGREWRITEAOF命令,啟動AOF重寫過程。
$ redis-cli
127.0.0.1:6379> BGREWRITEAOF
- Redis會返回一個后臺任務的ID,表示AOF重寫任務已經開始。
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started by pid 1234
- 可以使用INFO PERSISTENCE命令查看當前AOF文件的大小和重寫過程的狀態(tài),等待重寫完成即可。
127.0.0.1:6379> INFO PERSISTENCE
# Persistence
aof_enabled:1
aof_rewrite_in_progress:1
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:0
aof_current_rewrite_time_sec:14
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
需要注意的是,即使手動觸發(fā)AOF重寫,Redis也會在滿足一定條件時自動觸發(fā)AOF重寫,以保證AOF文件的大小和性能。
重寫規(guī)則通過配置中的 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 選項控制。
AOF 重寫面臨的問題
子進程在AOF重寫期間,父進程還是在繼續(xù)接收和處理命令的。
那么就存在一個問題:新的命令可能會對現有的數據庫狀態(tài)進行修改,從而使得服務器當前的數據庫狀態(tài)和重寫后的AOF文件所保存的數據庫狀態(tài)不一致。
圖片
如上圖,T1 時刻重寫前數據庫存儲的鍵只有 k1和k2,T2時刻發(fā)生重寫,在T3時刻重寫期間,客戶端新寫入了兩個鍵:k3和k4。T4時刻重寫結束。
可以觀察到,T4時刻重寫后的AOF文件和服務器當前的數據庫狀態(tài)并不一致,新的AOF文件只保存了k1和k2的兩個鍵的數據,而服務器數據庫現在卻有k1、k2、k3、k4 四個鍵。
AOF重寫緩存區(qū)
為了解決這種數據不一致問題,Redis服務器設置了一個AOF重寫緩沖區(qū)。
AOF重寫緩存區(qū)在AOF重寫時開始啟用,當Redis服務器執(zhí)行完一個寫命令之后,它會同時將這個寫命令發(fā)送給AOF緩沖區(qū)和AOF重寫緩沖區(qū)。
示意圖如下:
圖片
由了AOF重寫緩存區(qū)的存在,當子進程完成AOF重寫工作之后,它會向父進程發(fā)送一個信號,父進程在接到該信號之后,會調用處理函數,將AOF重寫緩沖區(qū)中的所有內容寫入到新AOF文件中(就是重寫后的文件),這樣重寫后數據庫狀態(tài)就和服務器當前的數據庫狀態(tài)一致了。
圖片
這里有個注意的點,AOF重寫緩存區(qū)同步至AOF文件中(上述紅色箭頭),這個過程是同步的,會阻塞父進程,在其他時候,AOF后臺重寫都不會阻塞父進程。
然后會對新的AOF文件進行改名,覆蓋現有的AOF文件,至此完成新舊兩個AOF文件的替換。
AOF重寫期間,命令會同步至AOF緩存區(qū)和AOF重寫緩沖區(qū),那么可不可以使用AOF緩存區(qū)代替AOF重寫緩沖區(qū)呢?
思考:AOF緩沖區(qū)可以替代AOF重寫緩沖區(qū)嗎?
先說結論:AOF緩沖區(qū)不可以替代AOF重寫緩沖區(qū)。
原因是AOF重寫緩沖區(qū)記錄的是從重寫開始后的所有需要重寫的命令,而AOF緩沖區(qū)可能只記錄了部分的命令(如果寫回的話,AOF緩存區(qū)的數據就會失效被丟失,因而只會保存一部分的命令,而AOF重寫緩存區(qū)不會)。
AOF相關配置
在 Redis 的配置文件 redis.conf 中,可以通過以下配置項來設置 AOF 相關參數:
- appendonly:該配置項用于開啟或關閉 AOF,默認為關閉。若開啟了 AOF,Redis 會在每次執(zhí)行寫命令時,將命令追加到 AOF 文件末尾。
- appendfilename:用于設置 AOF 文件名,默認為 appendonly.aof。
- appendfsync:該配置項用于設置 AOF 的同步機制。有三種可選值:
- always:表示每個寫命令都要同步到磁盤,安全性最高,但是性能較差。
- everysec:表示每秒同步一次,是默認選項,既能保證數據安全,又具有較好的性能。
- no:表示不進行同步,而是由操作系統(tǒng)決定何時將緩沖區(qū)中的數據同步到磁盤上,性能最好,但是安全性較低。
- auto-aof-rewrite-percentage和auto-aof-rewrite-min-size:這兩個配置項用于設置 AOF 重寫規(guī)則。當 AOF 文件大小超過 auto-aof-rewrite-min-size 設置的值,并且 AOF 文件增長率達到 auto-aof-rewrite-percentage 所定義的百分比時,Redis 會啟動 AOF 重寫操作。auto-aof-rewrite-percentage 默認值為100, auto-aof-rewrite-min-size 默認值為64mb。Redis會記錄上次重寫時的AOF大小,也就是說默認配置是當AOF文件大小是上次rewrite后大小的一倍且文件大于64M時觸發(fā)。
- aof-use-rdb-preamble:Redis 4版本新特性,混合持久化。AOF重寫期間是否開啟增量式同步,該配置項在AOF重寫期間是否使用RDB文件內容。默認是no,如果設置為yes,在AOF文件頭加入一個RDB文件的內容,可以盡可能的減小AOF文件大小,同時也方便恢復數據。
AOF 文件修復
服務器可能在程序正在對 AOF 文件進行寫入時停機,造成 AOF 文件損壞。
發(fā)生這種情況時,可以使用 Redis 自帶的 redis-check-aof 程序,對 AOF 文件進行修復,命令如下:
$ redis-check-aof –fix
AOF 寫后日志
我們比較熟悉的是數據庫的寫前日志(Write Ahead Log,WAL),也就是說,在實際寫數據前,先把修改的數據記到日志文件中,以便故障時進行恢復。
比如 MySQL Innodb 存儲引擎中的 redo log(重做日志)便是采用寫前日志。
不過,AOF 日志卻正好相反,它是寫后日志,“寫后”的意思是 Redis 是先執(zhí)行命令,把數據寫入內存,然后才記錄日志。
思考:為什么要這樣設計?
其實為了避免額外的檢查開銷,Redis 在向 AOF 里面記錄日志的時候,并不會先去對這些命令進行語法檢查。所以,如果先記日志再執(zhí)行命令的話,日志中就有可能記錄了錯誤的命令,Redis 在使用日志恢復數據時,就可能會出錯。
而寫后日志這種方式,就是先讓系統(tǒng)執(zhí)行命令,只有命令能執(zhí)行成功,才會被記錄到日志中,否則,系統(tǒng)就會直接向客戶端報錯。所以,Redis 使用寫后日志這一方式的一大好處是,可以避免出現記錄錯誤命令的情況,省下了語法檢查的性能開銷。
除此之外,AOF 寫后日志還有一個好處:它是在命令執(zhí)行后才記錄日志,所以并不會阻塞當前的寫操作。
不過,寫后日志也有兩個潛在的風險:
- 首先,如果剛執(zhí)行完一個命令,還沒有來得及記日志就宕機了,那么這個命令和相應的數據就有丟失的風險。如果此時 Redis 是用作緩存,還可以從后端數據庫重新讀入數據進行恢復,但是,如果 Redis 是直接用作數據庫的話,此時,因為命令沒有記入日志,所以就無法用日志進行恢復了。
- 其次,寫后日志雖然避免了對當前命令的阻塞,但可能會給下一個操作帶來阻塞風險。這是因為,AOF 日志也是在主線程中執(zhí)行的,如果在把日志文件寫入磁盤時,磁盤寫壓力大,就會導致寫盤很慢,進而導致后續(xù)的操作也無法執(zhí)行了。
混合持久化
在過去, Redis 用戶通常會因為 RDB 持久化和 AOF 持久化之間不同的優(yōu)缺點而陷入兩難的選擇當中:
- RDB 持久化能夠快速地儲存和恢復數據,但是在服務器停機時可能會丟失大量數據。
- AOF 持久化能夠有效地提高數據的安全性,但是在儲存和恢復數據方面卻要耗費大量的時間。
為了讓用戶能夠同時擁有上述兩種持久化的優(yōu)點, Redis 4.0 推出了一個“魚和熊掌兼得”的持久化方案 —— RDB-AOF 混合持久化。
這種持久化能夠通過 AOF 重寫操作創(chuàng)建出一個同時包含 RDB 數據和 AOF 數據的 AOF 文件, 其中 RDB 數據位于 AOF 文件的開頭, 它們儲存了服務器開始執(zhí)行重寫操作時的數據庫狀態(tài)。至于那些在重寫操作執(zhí)行之后執(zhí)行的 Redis 命令, 則會繼續(xù)以 AOF 格式追加到 AOF 文件的末尾, 也即是 RDB 數據之后。
也就是說當開啟混合持久化之后,AOF文件中的內容:前半部分是二進制的RDB內容,后面跟著AOF增加的數據,AOF位于兩次RDB之間。
格式會類似下面這樣:
圖片
在目前版本中, RDB-AOF 混合持久化功能默認是處于關閉狀態(tài)的, 要啟用該功能, 用戶不僅需要開啟 AOF 持久化功能, 還需要將 aof-use-rdb-preamble 選項的值設置為 true。
appendonly yes
aof-use-rdb-preamble yes
合適的持久化方式
當你想選擇適合你的應用程序的持久化方式時,你需要考慮以下兩個因素:
- 數據的實時性和一致性:如果對數據的實時性和一致性有很高的要求,則AOF可能是更好的選擇。如果對數據的實時性和一致性要求不太高,并且希望能快速地加載數據并減少磁盤空間的使用,那么RDB可能更適合你的應用程序。因為RDB文件是二進制格式的,結構非常緊湊,所以在Redis重啟時可以迅速地加載數據。
- Redis的性能需求:如果對Redis的性能有很高的要求,那么關閉持久化功能也是一個選擇。因為持久化功能可能會影響Redis的性能,但是一般不建議這么做。
總結
本篇文章到這就結束了,最后我們來做個小總結:
我們要意識到Redis的持久化機制扮演著至關重要的角色。RDB和AOF兩種主要的持久化方式各有其優(yōu)勢和使用場景。
RDB通過提供特定時間點的數據快照,對于災難恢復是非常有效的;而AOF則通過記錄每個寫入操作,提供了更好的數據持久性保證。然而,它們也有各自的局限性,這就需要根據實際需求來權衡選用哪種持久化方式。
最后,不可忽視的是,在選擇合適的持久化策略時,我們還應考慮如何平衡內存使用、磁盤使用、性能與持久性等多個因素。只有對Redis持久化的深入理解,我們才能充分利用其強大的功能,以滿足各種業(yè)務需求。