共計 5622 個字符,預計需要花費 15 分鐘才能閱讀完成。
丸趣 TV 小編給大家分享一下 Redis 中持久化機制是怎么樣的,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!
Redis 持久化機制
為什么要持久化
如果 Redis 再次訪問時,發現 Redis 的數據是空的,就會形成緩存穿透。更重要的是,因為 Redis 的數據是空的,所以客戶端想要訪問的 key 都沒有,就會造成大量的請求就會瞬間打到數據庫上,造成緩存雪崩(少量的 key 是穿透,大量的 key 是雪崩)。
這個時候,數據庫可能就掛掉。而又無法保證 redis 不宕機,所以需要當 redis 宕機后,迅速將里里面的內容恢復出來。因此需要做一個持久化。持久化是為了恢復數據用的,而不是存儲數據用的。
RDB
RDB(Redis DataBase),是 Redis 默認的存儲方式,RDB 方式是通過快照 (snapshotting) 完成的。
觸發快照的方式
符合自定義配置的快照規則
save 900 1 # 表示 15 分鐘 (900 秒鐘) 內至少 1 個鍵被更改則進行快照。
save 300 10 # 表示 5 分鐘 (300 秒) 內至少 10 個鍵被更改則進行快照。
save 60 10000 # 表示 1 分鐘內至少 10000 個鍵被更改則進行快
N 秒內數據集至少有 M 個改動”這一條件被滿足時,自動保存一次數據集。
執行 save 或者 bgsave 命令
執行命令 save 或 bgsave 可以生成 dump.rdb 文件,每次命令執行都會將所有 redis 內存快照到一個新的 rdb 文件里,并覆蓋原有 rdb 快照文件。
save 與 bgsave 對比:
命令 savebgsaveIO 類型同步異步是否阻塞 redis 其它命令是否 (在生成子進程執行調用 fork 函數時會有短暫阻塞) 復雜度 O(n)O(n)優點不會消耗額外內存不阻塞客戶端命令缺點阻塞客戶端命令需要 fork 子進程,消耗內存
配置自動生成 rdb 文件后臺使用的是 bgsave 方式。
執行 flushall
命令
flushall
清空 Redis 之前,保存當前 Redis 快照
執行主從復制操作 (第一次)
第一次主從復制時需要生成 rdb 文件,會保存當前 Redis 快照
RDB 執行流程
流程分析
父進程 fork 子進程后,繼續工作。
子進程發送信號給父進程表示完成,父進程更新統計信息。
子進程創建 RDB 文件,根據父進程內存快照生成臨時快照文件,完成后對原有文件進行原子替換。(RDB 始終完整)
父進程 fork 后,bgsave 命令返回”Background saving started”信息并不再阻塞父進程,并可以響應其他命令。
父進程執行 fork(調用操作系統函數復制主進程)操作創建子進程,這個過程中父進程是阻塞的,Redis 不能執行來自客戶端的任何命令。
Redis 父進程首先判斷: 當前是否在執行 save 或 bgsave/bgrewriteaof(aof 文件重寫命令)的子進程,如果在執行則 bgsave 命令直接返回。
RDB 文件結構
1、頭部 5 字節固定為“REDIS”字符串
2、4 字節“RDB”版本號(不是 Redis 版本號),當前為 9,填充后為 0009
3、輔助字段,以 key-value 的形式
4、存儲數據庫號碼
5、字典大小
6、過期 key
7、主要數據,以 key-value 的形式存儲
8、結束標志
9、校驗和,就是看文件是否損壞,或者是否被修改
RDB 的優缺點
優點
RDB 是二進制壓縮文件,占用空間小,便于傳輸(傳給 slaver)
主進程 fork 子進程,可以最大化 Redis 性能,主進程不能太大,復制過程中主進程阻塞
缺點
不保證數據完整性,會丟失最后一次快照以后更改的所有數據
AOF
AOF(append only file)是 Redis 的另一種持久化方式。Redis 默認情況下是不開啟的。開啟 AOF 持久化后,Redis 將所有對數據庫進行過寫入的命令 (及其參數)(RESP) 記錄到 AOF 文件,以此達到記錄數據庫狀態的目的,
這樣當 Redis 重啟后只要按順序回放這些命令就會恢復到原始狀態了。AOF 會記錄過程,RDB 只管結果
AOF 持久化實現
配置 redis.conf
# 可以通過修改 redis.conf 配置文件中的 appendonly 參數開啟
appendonly yes
# AOF 文件的保存位置和 RDB 文件的位置相同,都是通過 dir 參數設置的。
dir ./
# 默認的文件名是 appendonly.aof,可以通過 appendfilename 參數修改
appendfilename appendonly.aof
AOF 原理
AOF 文件中存儲的是 redis 的命令,同步命令到 AOF 文件的整個過程可以分為三個階段:
命令傳播:Redis 將執行完的命令、命令的參數、命令的參數個數等信息發送到 AOF 程序中。
緩存追加:AOF 程序根據接收到的命令數據,將命令轉換為網絡通訊協議的格式,然后將協議內容追加 到服務器的 AOF 緩存中。
文件寫入和保存:AOF 緩存中的內容被寫入到 AOF 文件末尾,如果設定的 AOF 保存條件被滿足的話,fsync 函數或者 fdatasync 函數會被調用,將寫入的內容真正地保存到磁盤中。
命令傳播
當一個 Redis 客戶端需要執行命令時,它通過網絡連接,將協議文本發送給 Redis 服務器。服務器在接到客戶端的請求之后,它會根據協議文本的內容,選擇適當的命令函數,并將各個參數從字符串文本轉換為 Redis 字符串對象(StringObject)。每當命令函數成功執行之后,命令參數都會被傳播到 AOF 程序。
緩存追加
當命令被傳播到 AOF 程序之后,程序會根據命令以及命令的參數,將命令從字符串對象轉換回原來的協議文本。協議文本生成之后,它會被追加到 redis.h/redisServer 結構的 aof_buf 末尾。
redisServer 結構維持著 Redis 服務器的狀態,aof_buf 域則保存著所有等待寫入到 AOF 文件的協議文本(RESP)
文件寫入和保存
每當服務器常規任務函數被執行、或者事件處理器被執行時,aof.c/flushAppendOnlyFile 函數都會被調用,這個函數執行以下兩個工作:
WRITE: 根據條件將 aof_buf 中的緩存寫入到 AOF 文件。
SAVE: 根據條件調用 fsync 或 fdatasync 函數將 AOF 文件保存到磁盤中。
AOF 保存模式
Redis 目前支持三種 AOF 保存模式,它們分別是:
AOF_FSYNC_NO : 不保存。
AOF_FSYNC_EVERYSEC : 每一秒鐘保存一次。(默認)
AOF_FSYNC_ALWAYS : 每執行一個命令保存一次。(不推薦)
AOF_FSYNC_NO
從不 fsync,將數據交給操作系統來處理。更快,也更不安全的選擇。
SAVE 只會在以下任意一種情況中被執行:
Redis 被關閉
AOF 功能被關閉
系統的寫緩存被刷新(可能是緩存已經被寫滿,或者定期保存操作被執行)
這三種情況下的 SAVE 操作都會引起 Redis 主進程阻塞。
AOF_FSYNC_EVERYSEC
SAVE 原則上每隔一秒鐘就會執行一次,因為 SAVE 操作是由后臺子線程 (fork) 調用的,所以它不會引起服務器主進程阻塞,并且在故障時只會丟失 1 秒鐘的數據。
AOF_FSYNC_ALWAYS
每次執行完一個命令之后,WRITE 和 SAVE 都會被執行。每次有新命令追加到 AOF 文件時就執行一次 fsync,非常慢,也非常安全。
因為 SAVE 是由 Redis 主進程執行的,所以在 SAVE 執行期間,主進程會被阻塞,不能接受命令請求。
AOF 保存模式對性能和安全性的影響
三種模式的比較
AOF 重寫
AOF 記錄數據的變化過程,越來越大,需要重寫“瘦身”
Redis 可以在 AOF 體積變得過大時,自動地在后臺(Fork 子進程)對 AOF 進行重寫。
重寫后的新 AOF 文件包含了恢復當前數據集所需的最小命令集合。
所謂的“重寫”其實是一個有歧義的詞語,實際上,AOF 重寫并不需要對原有的 AOF 文件進行任何寫入和讀取,它針對的是數據庫中鍵的當前值。
舉例說明
set s1 11
set s1 22
set s1 33
lpush list1 1 2 3
lpush list1 4 5 6
AOF 重寫后
set s1 33
lpush list1 1 2 3 4 5 6
Redis 不希望 AOF 重寫造成服務器無法處理請求,所以 Redis 決定將 AOF 重寫程序放到(后臺)子進程里執行,
1、子進程進行 AOF 重寫期間,主進程可以繼續處理命令請求。
2、子進程帶有主進程的數據副本,使用子進程而不是線程,可以在避免鎖的情況下,保證數據的安全性。
不過,使用子進程也有一個問題需要解決:因為子進程在進行 AOF 重寫期間,主進程還需要繼續處理命令,而新的命令可能對現有的數據進行修改,這會讓當前數據庫的數據和重寫后的 AOF 文件中的數據不一致。
為了解決這個問題,Redis 增加了一個 AOF 重寫緩存,這個緩存在 fork 出子進程之后開始啟用,Redis 主進程在接到新的寫命令之后,除了會將這個寫命令的協議內容追加到現有的 AOF 文件之外,還會追加到這個緩存中。
重寫過程分析
Redis 在創建新 AOF 文件的過程中,會繼續將命令追加到現有的 AOF 文件里面,即使重寫過程中發生停機,現有的 AOF 文件也不會丟失。而一旦新 AOF 文件創建完畢,Redis 就會從舊 AOF 文件切換到新 AOF 文件,并開始對新 AOF 文件進行追加操作。
當子進程在執行 AOF 重寫時,主進程需要執行以下三個工作:
處理命令請求。
將寫命令追加到現有的 AOF 文件中。
將寫命令追加到 AOF 重寫緩存中
。這樣一來可以保證:現有的 AOF 功能會繼續執行,即使在 AOF 重寫期間發生停機,也不會有任何數據丟失。所有對數據庫進行修改的命令都會被記錄到 AOF 重寫緩存中。
當子進程完成 AOF 重寫之后,它會向父進程發送一個完成信號,父進程在接到完成信號之后,會調用一個信號處理函數,并完成以下工作:
將 AOF 重寫緩存中的內容全部寫入到新 AOF 文件中。
對新的 AOF 文件進行改名,覆蓋原有的 AOF 文件。
Redis 數據庫里的 +AOF 重寫過程中的命令 ——- 新的 AOF 文件 —- 覆蓋老的當步驟 1 執行完畢之后,現有 AOF 文件、新 AOF 文件和數據庫三者的狀態就完全一致了。
當步驟 2 執行完畢之后,程序就完成了新舊兩個 AOF 文件的交替。這個信號處理函數執行完畢之后,主進程就可以繼續像往常一樣接受命令請求了
。在整個 AOF 后臺重寫過程中,只有最后的寫入緩存和改名操作會造成主進程阻塞,在其他時候,AOF 后臺重寫都不會對主進程造成阻塞,這將 AOF 重寫對性能造成的影響降到了最低。
AOF 重寫觸發方式
1、配置觸發
# 表示當前 aof 文件大小超過上一次 aof 文件大小的百分之多少的時候會進行重寫。如果之前沒有重寫過,以啟動時 aof 文件大小為準
auto-aof-rewrite-percentage 100
#限制允許重寫最小 aof 文件大小,也就是文件大小小于 64mb 的時候,不需要進行優化
auto-aof-rewrite-min-size 64mb
2、執行 bgrewriteaof 命令
127.0.0.1:6379 bgrewriteaof‘Backgroundappendonlyfilerewritingstarted
AOF 重寫總結
混合持久化
RDB 和 AOF 各有優缺點,Redis 4.0 開始支持 rdb 和 aof 的混合持久化。
如果把混合持久化打開,aofrewrite 的時候就直接把 rdb 的內容寫到 aof 文件開頭。
RDB 的頭 +AOF 的身體 —- appendonly.aof
開啟混合持久化
aof-use-rdb-preambleyes
AOF 文件的載入與數據還原
如果開啟了混合持久化,AOF 在重寫時,不再是單純將內存數據轉換為 RESP 命令寫入 AOF 文件,而是將重寫這一刻之前的內存做 RDB 快照處理,并且將 RDB 快照內容和增量的 AOF 修改內存數據的命令存在一起,都寫入新的 AOF 文件,新的文件一開始不叫 appendonly.aof,等到重寫完新的 AOF 文件才會進行改名,覆蓋原有的 AOF 文件,完成新舊兩個 AOF 文件的替換。
于是在 Redis 重啟的時候,可以先加載 RDB 的內容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,因此重啟效率大幅得到提升。
1、創建一個不帶網絡連接的偽客戶端(fake client)
因為 Redis 的命令只能在客戶端上下文中執行,而載入 AOF 文件時所使用的命令直接來源于 AOF 文件而不是網絡連接,所以服務器使用了一個沒有網絡連接的偽客戶端來執行 AOF 文件保存的寫命令,偽客戶端執行命令的效果和帶網絡連接的客戶端執行命令的效果完全一樣
2、從 AOF 文件中分析并讀取出一條寫命令
3、使用偽客戶端執行被讀出的寫命令
4、一直執行步驟 2 和步驟 3,直到 AOF 文件中的所有寫命令都被處理完畢為止
Redis 數據備份策略
1. 寫 crontab 定時調度腳本,每小時都 copy 一份 rdb 或 aof 的備份到一個目錄中去,僅僅保留最近 48 小時的備份
2. 每天都保留一份當日的數據備份到一個目錄中去,可以保留最近 1 個月的備份
3. 每次 copy 備份的時候,都把太舊的備份給刪了
4. 每天晚上將當前機器上的備份復制一份到其他機器上,以防機器損壞
RDB 和 AOF 對比
1、RDB 存某個時刻的數據快照,采用二進制壓縮存儲,AOF 存操作命令,采用文本存儲(混合)
2、RDB 性能高、AOF 性能較低
3、RDB 在配置觸發狀態會丟失最后一次快照以后更改的所有數據,AOF 設置為每秒保存一次,則最多丟 2 秒的數據
4、Redis 以主服務器模式運行,RDB 不會保存過期鍵值對數據,Redis 以從服務器模式運行,RDB 會保存過期鍵值對,當主服務器向從服務器同步時,再清空過期鍵值對。AOF 寫入文件時,對過期的 key 會追加一條 del 命令,當執行 AOF 重寫時,會忽略過期 key 和 del 命令。
看完了這篇文章,相信你對“Redis 中持久化機制是怎么樣的”有了一定的了解,如果想了解更多相關知識,歡迎關注丸趣 TV 行業資訊頻道,感謝各位的閱讀!