快速理解Redis的持久化

Redis系列文章

爲何須要持久化

很簡單,由於 Redis基於內存的。數據若是不進行持久化,當服務器重啓或者宕機的時候數據是沒法恢復的,因此爲了保證數據的安全性,咱們須要將內存中的數據持久化到磁盤中。安全

Redis的持久化

Redis 提供了兩種持久化的方式,分別是 RDBAOF服務器

  • RDB : Redis的默認持久化方式,是基於 快照 來實現的,當符合必定條件的時候 Redis 會自動將內存中的數據進行快照而後持久化到磁盤中。
  • AOF : Redis默認沒有開啓 AOF 持久化,須要在配置文件中設置 appendonly true 開啓。它存儲的是 Redis順序指令序列

RDB方式的持久化

save 阻塞方式

Redis 中有一個命令能夠觸發 RDB 持久化,可是這個操做會阻塞 Redis數據結構

這個命令是 save,咱們都知道 Redis 是單線程的,若是持久化進行 特殊的處理 的話,那麼就會阻塞其餘命令致使 Redis 短期內不可用,若是 RDB 文件很大,那麼刷盤操做將會數十秒,嚴重影響可用性,因此咱們通常都不會使用 save 命令。app

bgsave 後臺方式

bgsave 顧名思義,就是 後臺進行保存 。當執行這條命令的時候 Redis 就會進行一些 特殊處理函數

什麼特殊處理呢?post

首先 Redis 的主進程會調用 glibc 的函數 fork 產生一個子進程,此時會將文件 持久化所有交給子進程去處理,那麼這時父進程就能夠繼續處理用戶的請求了(bgsave執行以後直接會返回)。固然,在主進程進行 fork 操做的時候可能也會對用戶請求命令 產生短暫的阻塞性能

凡事有利必有弊,你看 bgsave 這麼好,難道沒有缺點麼? 答案是有的,在哪呢?咱們先來了解一下 COW 機制吧。spa

COW

COW (copy on write),也就是 寫時複製 。咱們知道 RDB 持久化須要遍歷內存中的數據,就像下面那張圖同樣。 操作系統

由於咱們須要的是在子進程產生的那一瞬間的數據(快照),若是此時由於用戶請求在主進程修改了內存中的數據,那麼子進程遍歷的內存就會被更改,這個時候就不是快照數據了。 線程

因此這裏就使用了產生快照的一種機制—— COW 。咱們知道上面的數據段其實由不少操做系統的組合而成的。COW 其實就是在主進程須要修改內存中的數據的時候,首先將須要修改的數據所在的頁進行復制,而後再複製的頁面上進行修改當進行頁的複製的時候就會佔用額外的內存,這也是 bgsave 佔用內存比 save 多的緣由,可是不用過度擔憂,由於再保存期間不會出現大量的用戶請求來修改數據,額外使用的內存也不會不少。

自動觸發RDB

Redis 中會有幾種狀況下進行 RDB 的持久化,因此即便你在配置文件中關閉了 RDBRedis 仍是會進行 RDB 的持久化。

  • 知足條件時

    Redis 的配置文件中有這麼三條配置。

    save 900 1
    save 300 10
    save 60 10000
    複製代碼

    這其實就是 RDB 中默認開啓的緣由,它的格式是這樣的 save seconds changeTimessave 後面的第一個數字是時間,第二個數字是修改次數,這三條配置的意思就是 在900秒內進行了1次修改或者在300秒內進行了10次修改或者在60秒內進行了10000次修改 會進行 RDB 的自動持久化。

  • shutdownRedis 正常關閉的時候會進行 RDB 持久化。

  • flushall 會產生一個空的 RDB 文件

  • 主從複製進行全量複製的時候(目前作了解就行,我在後面的文章會講到 Redis 集羣)

RDB的優勢

  • RDB 文件,其中作了些壓縮,存儲的是數據,能夠快速的進行災難恢復
  • 適合作冷備。

RDB的缺點

  • 容易丟失數據,由於 RDB 須要遍歷整個內存中的全部數據,因此進行一次 RDB 操做是一個費事費力的操做,爲了保證 Redis 的高性能,你須要儘可能減小 RDB 的持久化,因此你可能會丟失一段時間的數據。

AOF方式的持久化

默認狀況下 Redis 是沒有開啓 AOF 持久化的,你須要在配置文件中進行相應的配置。

appendonly yes   # 默認爲no這裏設置yes開啓
dir ./           # aof文件目錄
appendfilename "appendonly-6379.aof" #aof文件名
複製代碼

開啓 AOF 持久化以後,Redis 會根據 AOF 持久化策略 來進行相應的持久化操做,具體配置是在 appendfsync 配置。

# appendfsync always  每次進行修改操做就進行寫盤
appendfsync everysec  每秒進行一些寫盤
# appendfsync no      從不
複製代碼

Redis一共提供了三個參數,通常考慮設置 everysec 每秒寫盤,這樣既能少影響效率也能減小數據丟失量。

AOF原理

AOF 日誌中存放的是對於 Redis 的操做指令,有了 AOF 日誌咱們就可使用它進行對 Redis 的重放。

好比此時咱們 AOF 日誌中記錄了 set hello worldsadd userset FancisQ 這兩條命令,咱們就能夠對一個空的 Redis 實例進行此 AOF 文件的重放,最終這個空的 Redis 就有了上面兩條記錄。

你可能會發現 Redis 中的這兩個持久化方式很像 MySQL 中的 bin logredo log,可是你須要注意的是 Redis 中的 AOF先執行命令再存日誌的。這和 MySQL 中的 WAL 機制截然相反。

爲何呢? 我以爲有兩點。

  1. Redis 是弱事務的,咱們不須要保證數據的強一致。在 MySQL 中咱們使用了 redo log 兩階段提交 來保證了 save-crash 能力,而在 Redis 中咱們顯然不須要這麼作,假設這條命令執行完以後還沒來得及寫日誌就宕機了,那就沒了,由於弱事務,咱們大可沒必要保證數據必須存在。
  2. 爲了不錯誤指令的日誌存儲,若是先寫日誌也就意味着咱們一開始沒有作相應的 邏輯處理和參數校驗 ,因此這樣會 先記錄到不少錯誤指令 ,可是咱們知道 AOF 文件是須要 瘦身 的,這些錯誤指令會給 AOF 瘦身帶來不少麻煩。

AOF重寫

上面提到的 瘦身 其實就是 AOF重寫 ,咱們知道 AOF 文件中存儲的是指令順序,當 Redis 長時間運行時會產生不少指令。

好比 set a b,set a c,set a d.....

其實上面三條就是對 key 爲 a 的數據進行操做了,在 RDB 中它可能只存了 a = d ,可是由於 AOF 的指令機制,它必須存在三條,但前面的是無心義的,這樣會浪費不少空間而且給 AOF 重放帶來麻煩。

因此 Redis 會在 AOF文件過大(符合某種條件)的時候進行自動的 AOF 重寫。對應的在配置文件中有這樣兩條配置。

# 下面兩條須要同時知足
# 表示當前 aof 文件超過上次 aof文件大小的百分之多少時會進行重寫,若是沒有重寫過則以啓動時的大小爲標準
auto-aof-rewrite-percentage 100 
# 文件大於多少的時候進行重寫
auto-aof-rewrite-min-size 64mb
複製代碼

那麼,AOF 是如何重寫的呢?

bgrewriteaof

這是一條 AOF 重寫命令(上述的重寫過程其實就是 bgrewriteaof),和 bgsave 同樣,Redis 也是會 fork 一個子進程,讓子進程去負責 AOF 文件的重寫。大體流程以下:

AOF的優缺點

  • 缺點: 在同等數據量的狀況下,AOF 文件的大小要比 RDB 文件大得多,若是使用它進行內存狀態恢復須要花費很長時間
  • 優勢: 持久化快,能減小數據丟失的量,在配置 everysec 的狀況下最多隻會丟失秒級的數據。

Redis混合持久化

Redis 4.0以前,咱們通常會開啓 AOF 而後再須要恢復內存狀態的時候棄用 AOF日誌重放 ( 若是使用RDB的話會丟失大量數據 )。但若是 Redis 實例很大,AOF 文件也很大的時候會致使 Redis 重啓很是慢。

爲了解決這個問題,在 Redis 4.0以後咱們能夠將 RDB文件和 AOF增量日誌存儲在一塊兒。若是這個時候咱們進行內存狀態恢復能夠先使用前面的 RDB 部分,而後再使用 RDB 持久化以後產生的增量AOF日誌 來進行內存狀態恢復以減小時間。

如何選擇 RDB 和 AOF

  • 通常來講若是對數據的安全性仍是有必定要求的話,應該同時使用兩種持久化功能
  • 若是能夠承受分鐘級別的數據丟失能夠僅僅使用 RDB
  • AOF 儘可能使用 everysec 配置,既能保證數據安全又能保證性能效率。
  • RDB 下關閉 save seconds changeTimes 這個自動持久化機制,或者合理使用參數。

思惟圖譜

感謝閱讀。 給大家分享一下思惟導圖 (#^.^#)

相關文章
相關標籤/搜索