天天看點

談談Redis中兩種常用持久化機制RDB和AOF一、Redis持久化機制介紹二、RDB持久化三、AOF持久化四、RDB和AOF到底該如何選擇

談談Redis中兩種常用持久化機制RDB和AOF

  • 一、Redis持久化機制介紹
  • 二、RDB持久化
    • I、觸發機制
      • 1、save觸發方式(手動觸發)
      • 2、bgsave觸發方式(手動觸發)
      • 3、自動觸發
        • save m n的實作原理
    • II、RDB檔案
    • III、優勢和劣勢
      • RDB優勢
      • RDB劣勢
  • 三、AOF持久化
    • I、觸發機制
      • 1、bgrewriteaof觸發(手動觸發)
      • 2、自動觸發
    • II、AOF工作原理
    • III. AOF緩沖區同步檔案政策
      • 1、appendfsync no 不儲存
      • 2、appendfsync everysec 每一秒鐘儲存一次
      • 3、appendfsync always 每執行一個指令儲存一次
    • IV、AOF優勢和劣勢
      • AOF優勢
      • AOF劣勢
  • 四、RDB和AOF到底該如何選擇

對于我們的企業來說,一個企業級别的redis架構持久化的操作是必不可少的!

那麼我們今天就來學習一下redis的兩種持久化方式吧!

一、Redis持久化機制介紹

RDB(Redis DataBase)和AOF(Append Only File)兩種持久化機制的介紹:

  1. RDB持久化機制,其實就是把資料以快照的形式儲存在磁盤上。什麼是快照呢,你可以了解成把目前時刻的資料拍成一張照片儲存下來。RDB持久化是指在指定的時間間隔内将記憶體中的資料集快照寫入磁盤,也是預設的持久化方式,這種方式是就是将記憶體中資料以快照的方式寫入到二進制檔案中,預設的檔案名為dump.rdb。
  2. AOF機制對每條寫入指令作為日志,以append-only的模式寫入一個日志檔案中,在redis重新開機的時候,可以通過回放AOF日志中的寫入指令來重新建構整個資料集。
  3. 通過RDB或AOF,都可以将redis記憶體中的資料給持久化到磁盤上,然後可以将這些資料備份到别的地方,比如說阿裡雲,華為雲等雲服務。此時如果redis挂了,伺服器上的記憶體和磁盤上的資料都丢了,可以從雲服務上拷貝回來之前的資料,放到指定的目錄中,然後重新啟動redis,redis就會自動根據持久化資料檔案中的資料,去恢複記憶體中的資料,繼續對外提供服務。

注意 1:如果RDB和AOF兩種持久化機制同時啟用,那麼在redis重新開機的時候,會使用AOF來重新建構資料,因為AOF中的資料更加完整(優先加載)

注意 2:如果我們想要redis僅僅作為純記憶體的緩存來用,那麼可以禁止RDB和AOF的持久化機制

二、RDB持久化

I、觸發機制

既然RDB機制是通過把某個時刻的所有資料生成一個快照來儲存,那麼就應該存在觸發機制,來實作這個過程。對于RDB來說,觸發分為手動觸發(save、bgsave)和自動觸發兩種,我們分别來看一下

1、save觸發方式(手動觸發)

該指令會阻塞目前Redis伺服器,執行save指令期間,Redis不能處理其他指令,直到RDB過程完成為止。具體流程如下:

談談Redis中兩種常用持久化機制RDB和AOF一、Redis持久化機制介紹二、RDB持久化三、AOF持久化四、RDB和AOF到底該如何選擇

執行完成時候如果存在老的RDB檔案,就把新的替代掉舊的。我們的用戶端可能都是幾萬或者是幾十萬,這種方式顯然不可取。

文法:

redis 127.0.0.1:6379> SAVE #啟動save指令

2、bgsave觸發方式(手動觸發)

執行該指令時,Redis會在背景異步進行快照操作,快照同時還可以響應用戶端請求。具體流程如下:

談談Redis中兩種常用持久化機制RDB和AOF一、Redis持久化機制介紹二、RDB持久化三、AOF持久化四、RDB和AOF到底該如何選擇

具體操作是Redis程序執行fork操作建立子程序,RDB持久化過程由子程序負責,完成後自動結束。阻塞隻發生在fork階段,一般時間很短。基本上 Redis 内部所有的RDB操作都是采用 bgsave 指令。

文法:

redis 127.0.0.1:6379> BGSAVE #啟動bgsave背景服務

3、自動觸發

自動觸發是由我們的配置檔案來完成的。在redis.conf配置檔案中,裡面有如下配置,我們可以去設定:

  1. save: 這裡是用來配置觸發 Redis的 RDB 持久化條件,也就是什麼時候将記憶體中的資料儲存到硬碟。比如“save m n”。表示m秒内資料集存在n次修改時,自動觸發bgsave。

    預設如下配置:

    #表示900 秒内如果至少有 1 個 key 的值變化,則儲存save 900 1#表示300 秒内如果至少有 10 個 key 的值變化,則儲存save 300 10#表示60 秒内如果至少有 10000 個 key 的值變化,則儲存save 60 10000

    不需要持久化,那麼你可以注釋掉所有的 save 行來停用儲存功能。

  2. stop-writes-on-bgsave-error : 預設值為yes。當啟用了RDB且最後一次背景儲存資料失敗,Redis是否停止接收資料。這會讓使用者意識到資料沒有正确持久化到磁盤上,否則沒有人會注意到災難(disaster)發生了。如果Redis重新開機了,那麼又可以重新開始接收資料了
  3. rdbcompression : 預設值是yes。對于存儲到磁盤中的快照,可以設定是否進行壓縮存儲。
  4. rdbchecksum : 預設值是yes。在存儲快照後,我們還可以讓redis使用CRC64算法來進行資料校驗,但是這樣做會增加大約10%的性能消耗,如果希望擷取到最大的性能提升,可以關閉此功能。
  5. dbfilename : 設定快照的檔案名,預設是 dump.rdb
  6. dir: 設定快照檔案的存放路徑,這個配置項一定是個目錄,而不能是檔案名。

我們可以修改這些配置來實作我們想要的效果。因為第三種方式是配置的,是以我們對前兩種進行一個對比:

談談Redis中兩種常用持久化機制RDB和AOF一、Redis持久化機制介紹二、RDB持久化三、AOF持久化四、RDB和AOF到底該如何選擇

save m n的實作原理

是将資料先存儲在記憶體,然後當資料累計達到某些設定的伐值的時候,就會觸發一次DUMP操作,将變化的資料一次性寫入資料檔案(RDB檔案)。

RDB實際是在Redis内部一個定時器事件,每隔固定時間去檢查目前資料發生的改變次數與時間是否滿足配置的持久化觸發的條件,如果滿足則通過作業系統fork調用來建立出一個子程序,這個子程序預設會與父程序共享相同的位址空間,這時就可以通過子程序來周遊整個記憶體來進行存儲操作,而主程序則仍然可以提供服務,當有寫入時由作業系統按照記憶體頁(page)為機關來進行copy-on-write保證父子程序之間不會互相影響。

具體實作:是通過serverCron函數、dirty計數器、和lastsave時間戳來實作的。

redis.c檔案的周期性函數serverCron:

/* This is our timer interrupt, called server.hz times per second.
 * Here is where we do a number of things that need to be done asynchronously.
 * For instance:
 *
 * - Active expired keys collection (it is also performed in a lazy way on
 *   lookup).
 * - Software watchdog.
 * - Update some statistic.
 * - Incremental rehashing of the DBs hash tables.
 * - Triggering BGSAVE / AOF rewrite, and handling of terminated children.
 * - Clients timeout of different kinds.
 * - Replication reconnection.
 * - Many more...
 *
 * Everything directly called here will be called server.hz times per second,
 * so in order to throttle execution of things we want to do less frequently
 * a macro is used: run_with_period(milliseconds) { .... }
 */

int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {

           

erverCron是Redis伺服器的周期性操作函數,預設每隔100ms執行一次;該函數對伺服器的狀态進行維護,其中一項工作就是檢查 save m n 配置的條件是否滿足,如果滿足就執行bgsave。

dirty計數器是Redis伺服器維持的一個狀态,記錄了上一次執行bgsave/save指令後,伺服器狀态進行了多少次修改(包括增删改);而當save/bgsave執行完成後,會将dirty重新置為0。

例如,如果Redis執行了set mykey helloworld,則dirty值會+1;如果執行了sadd myset v1 v2 v3,則dirty值會+3;注意dirty記錄的是伺服器進行了多少次修改,而不是用戶端執行了多少修改資料的指令。

astsave時間戳也是Redis伺服器維持的一個狀态,記錄的是上一次成功執行save/bgsave的時間。 =

save m n的原理如下:每隔100ms,執行serverCron函數;在serverCron函數中,周遊save m n配置的儲存條件,隻要有一個條件滿足,就進行bgsave。對于每一個save m n條件,隻有下面兩條同時滿足時才算滿足:

(1)目前時間-lastsave > m

(2)dirty >= n

save m n 執行日志

其他自動觸發機制

除了save m n 以外,還有一些其他情況會觸發bgsave:

在主從複制場景下,如果從節點執行全量複制操作,則主節點會執行bgsave指令,并将rdb檔案發送給從節點

執行shutdown指令時,自動執行rdb持久化。

II、RDB檔案

RDB檔案是經過壓縮的二進制檔案,下面介紹關于RDB檔案的一些細節。

存儲路徑: RDB檔案的存儲路徑既可以在啟動前配置,也可以通過指令動态設定。

配置: dir配置指定目錄,dbfilename指定檔案名。預設是Redis根目錄下的dump.rdb檔案。

動态設定: Redis啟動後也可以動态修改RDB存儲路徑,在磁盤損害或空間不足時非常有用;執行指令為config set dir {newdir}和config set dbfilename {newFileName}

談談Redis中兩種常用持久化機制RDB和AOF一、Redis持久化機制介紹二、RDB持久化三、AOF持久化四、RDB和AOF到底該如何選擇
  1. REDIS:常量,儲存着”REDIS”5個字元。
  2. db_version:RDB檔案的版本号,注意不是Redis的版本号。
  3. SELECTDB 0 pairs:表示一個完整的資料庫(0号資料庫),同理SELECTDB 3 pairs表示完整的3号資料庫;隻有當資料庫中有鍵值對時,RDB檔案中才會有該資料庫的資訊(上圖所示的Redis中隻有0号和3号資料庫有鍵值對);如果Redis中所有的資料庫都沒有鍵值對,則這一部分直接省略。其中:SELECTDB是一個常量,代表後面跟着的是資料庫号碼;0和3是資料庫号碼;pairs則存儲了具體的鍵值對資訊,包括key、value值,及其資料類型、内部編碼、過期時間、壓縮資訊等等。
  4. EOF:常量,标志RDB檔案正文内容結束。
  5. check_sum:前面所有内容的校驗和;Redis在載入RBD檔案時,會計算前面的校驗和并與check_sum值比較,判斷檔案是否損壞。

Redis預設采用LZF算法對RDB檔案進行壓縮。雖然壓縮耗時,但是可以大大減小RDB檔案的體積,是以壓縮預設開啟;可以通過指令關閉:

config set rdbcompression no
談談Redis中兩種常用持久化機制RDB和AOF一、Redis持久化機制介紹二、RDB持久化三、AOF持久化四、RDB和AOF到底該如何選擇

需要注意的是,RDB檔案的壓縮并不是針對整個檔案進行的,而是對資料庫中的字元串進行的,且隻有在字元串達到一定長度(20位元組)時才會進行。

III、優勢和劣勢

RDB優勢

  • 備份政策友善: 一旦采用該方式,那麼你的整個Redis資料庫将隻包含一個檔案,這對于檔案備份而言是非常完美的。比如,你可能打算每個小時歸檔一次最近24小時的資料,同時還要每天歸檔一次最近30天的資料。通過這樣的備份政策,一旦系統出現災難性故障,我們可以非常容易的進行恢複。
  • 災難恢複友善: RDB是非常不錯的選擇。因為我們可以非常輕松的将一個單獨的檔案壓縮後再轉移到其它存儲媒體上。
  • 性能最大化: 對于Redis的服務程序而言,在開始持久化時,它唯一需要做的隻是fork出子程序,之後再由子程序完成這些持久化的工作,這樣就可以極大的避免服務程序執行IO操作了。
  • 啟動效率高: 相比于AOF機制,如果資料集很大,RDB的啟動效率會更高。

RDB劣勢

  • 不能實時持久化: 如果你想保證資料的高可用性,即最大限度的避免資料丢失,那麼RDB将不是一個很好的選擇。因為系統一旦在定時持久化之前出現當機現象,此前沒有來得及寫入磁盤的資料都将丢失。
  • 影響性能: 由于RDB是通過fork子程序來協助完成資料持久化工作的,是以,如果當資料集較大時,可能會導緻整個伺服器停止服務幾百毫秒,甚至是1秒鐘。
  • 版本相容RDB格式問題

三、AOF持久化

I、觸發機制

AOF方式實際類似mysql的基于語句的binlog方式,即每條會使Redis記憶體資料發生改變的指令都會追加到一個log檔案中,也就是說這個log檔案就是Redis的持久化資料。AOF觸發也分為手動觸發(bgrewriteaof)和自動觸發兩種。

1、bgrewriteaof觸發(手動觸發)

使用bgrewriteaof指令:Redis主程序fork子程序來執行AOF重寫,這個子程序建立新的AOF檔案來存儲重寫結果,防止影響舊檔案。因為fork采用了寫時複制機制,子程序不能通路在其被建立出來之後産生的新資料。Redis使用“AOF重寫緩沖區”儲存這部分新資料,最後父程序将AOF重寫緩沖區的資料寫入新的AOF檔案中然後使用新AOF檔案替換老檔案。

127.0.0.1:6379> bgrewriteoaf

OK

2、自動觸發

和RDB一樣,配置在redis.conf檔案裡:

  • appendonly: 是否打開AOF持久化功能,appendonly預設是 no, 改成appendonly yes。
  • appendfilename: AOF檔案名稱
  • appendfsync: 同步頻率
  • auto-aof-rewrite-min-size: 如果檔案大小小于此值不會觸發AOF,預設64MB
  • auto-aof-rewrite-percentage: Redis記錄最近的一次AOF操作的檔案大小,如果目前AOF檔案大小增長超過這個百分比則觸發一次重寫,預設100

啟用AOF:

appendonly yes

關閉aof:

  • 指令行關閉: 關閉aof的指令:config set appendfsync no
  • 配置檔案: 将appendonly設定為no,預設是 appendonly no )

II、AOF工作原理

是将資料也是先存在記憶體,但是在存儲的時候會使用調用fsync來完成對本次寫操作的日志記錄,這個日志檔案其實是一個基于Redis網絡互動協定的文本檔案。AOF調用fsync也不是說全部都是無阻塞的,在某些系統上可能出現fsync阻塞程序的情況,對于這種情況可以通過配置修改,但預設情況不要修改。AOF最關鍵的配置就是關于調用fsync追加日志檔案的平率,有兩種預設頻率,always每次記錄進來都添加,everysecond 每秒添加一次。

同步指令到 AOF 檔案的整個過程可以分為三個階段:

  • 指令寫入:Redis 将執行完的指令、指令的參數、指令的參數個數等資訊發送到 AOF 程式中。
  • 追加AOF緩存:AOF 程式根據接收到的指令資料, 然後每隔一定的時間(比如每隔一秒)将協定内容寫入AOF 緩沖區中。
  • 檔案寫入儲存:當達到 AOF同步條件,fsync 函數或者 fdatasync 函數會被調用,将 OS Cache 中的資料寫入磁盤檔案。

随着AOF檔案越來越大,需要定期對AOF檔案進行重寫,達到壓縮的目的。

談談Redis中兩種常用持久化機制RDB和AOF一、Redis持久化機制介紹二、RDB持久化三、AOF持久化四、RDB和AOF到底該如何選擇

III. AOF緩沖區同步檔案政策

Redis 目前支援三種 AOF 儲存模式,Redis的配置appendfsync 中存在三種同步方式,它們分别是:

  • AOF_FSYNC_NO : 不儲存。
  • AOF_FSYNC_EVERYSEC : 每一秒鐘儲存一次、該政策為AOF的預設政策。
  • AOF_FSYNC_ALWAYS : 每執行一個指令儲存一次

對應redis配置:

  • appendfsync no: 寫入aof檔案,不等待磁盤同步。
  • appendfsync always: 總是寫入aof檔案,并完成磁盤同步。
  • appendfsync everysec: 每一秒寫入aof檔案,并完成磁盤同步。

從持久化角度講,always是最安全的。從效率上講,no是最快的。而redis預設設定進行了折中,選擇了everysec。合情合理。

1、appendfsync no 不儲存

指令寫入aof緩沖區後,在寫入系統緩沖區直接傳回(系統調用write寫入os cache),然後有專門線程每秒執行寫入磁盤(阻塞,系統調用fsync)後傳回。當設定appendfsync為no的時候,Redis不會主動調用fsync去将AOF日志内容同步到磁盤,是以這一切就完全依賴于作業系統的調試了。對大多數Linux作業系統,是每30秒進行一次fsync,将緩沖區中的資料寫到磁盤上。

在這種模式下, 每次調用

flushAppendOnlyFile

函數,write(寫入os cache)都會被執行, 但save(fsync)會被略過。

在這種模式下, SAVE 隻會在以下任意一種情況中被執行:

  • Redis 被關閉
  • AOF 功能被關閉
  • 系統的寫緩存被重新整理(可能是緩存已經被寫滿,或者定期儲存操作被執行)

這三種情況下的 SAVE 操作都會引起 Redis 主程序阻塞。

2、appendfsync everysec 每一秒鐘儲存一次

在這種模式中, SAVE原則上每隔一秒鐘就會執行一次, 因為SAVE操作是由背景子線程調用的, 是以它不會引起伺服器主程序阻塞。 注意, 在上一句的說明裡面使用了詞語“原則上”, 在實際運作中, Redis主程序在這種模式下對

fsync/fdatasync

的調用并不是每秒一次, 它和調用

flushAppendOnlyFile

函數時 Redis 所處的狀态有關。

每當

flushAppendOnlyFile

函數被調用時, 可能會出現以下四種情況:

談談Redis中兩種常用持久化機制RDB和AOF一、Redis持久化機制介紹二、RDB持久化三、AOF持久化四、RDB和AOF到底該如何選擇

根據以上說明可以知道, 在“每一秒鐘儲存一次”模式下, 如果在情況 1 中發生故障停機, 那麼使用者最多損失小于 2 秒内所産生的所有資料。

如果在情況 2 中發生故障停機, 那麼使用者損失的資料是可以超過 2 秒的。

Redis 官網上所說的, AOF 在“每一秒鐘儲存一次”時發生故障, 隻丢失 1 秒鐘資料的說法, 實際上并不準确。

3、appendfsync always 每執行一個指令儲存一次

在這種模式下,每次執行完一個指令之後, WRITE 和 SAVE 都會被執行。

另外,因為 SAVE 是由 Redis 主程序執行的,是以在 SAVE 執行期間,主程序會被阻塞,不能接受指令請求。

IV、AOF優勢和劣勢

AOF優勢

  • 資料安全性: 該機制可以帶來更高的資料安全性,即資料持久性。Redis中提供了3中同步政策,即每秒同步、每修改同步和不同步。事實上,每秒同步也是異步完成的,其效率也是非常高的,所差的是一旦系統出現當機現象,那麼這一秒鐘之内修改的資料将會丢失。而每修改同步,我們可以将其視為同步持久化,即每次發生的資料變化都會被立即記錄到磁盤中。可以預見,這種方式在效率上是最低的。
  • 資料一緻性: 由于該機制對日志檔案的寫入操作采用的是append模式,是以在寫入過程中即使出現當機現象,也不會破壞日志檔案中已經存在的内容。然而如果我們本次操作隻是寫入了一半資料就出現了系統崩潰問題,不用擔心,在Redis下一次啟動之前,我們可以通過redis-check-aof工具來幫助我們解決資料一緻性的問題。

如果日志過大,Redis可以自動啟用rewrite機制。即Redis以append模式不斷的将修改資料寫入到老的磁盤檔案中,同時Redis還會建立一個新的檔案用于記錄此期間有哪些修改指令被執行。是以在進行rewrite切換時可以更好的保證資料安全性。

AOF包含一個格式清晰、易于了解的日志檔案用于記錄所有的修改操作。事實上,我們也可以通過該檔案完成資料的重建。

AOF劣勢

  • 恢複速度慢: 對于相同數量的資料集而言,AOF檔案通常要大于RDB檔案。RDB 在恢複大資料集時的速度比 AOF 的恢複速度要快。
  • 性能低: 根據同步政策的不同,AOF在運作效率上往往會慢于RDB。總之,每秒同步政策的效率是比較高的,同步禁用政策的效率和RDB一樣高效。

四、RDB和AOF到底該如何選擇

選擇的話,兩者加一起才更好。因為兩個持久化機制你明白了,剩下的就是看自己的需求了,需求不同選擇的也不一定,但是通常都是結合使用。有一張圖可供總結:

談談Redis中兩種常用持久化機制RDB和AOF一、Redis持久化機制介紹二、RDB持久化三、AOF持久化四、RDB和AOF到底該如何選擇

繼續閱讀