1. 程式人生 > >深入Redis的RDB和AOF兩種持久化方式以及AOF重寫機制的分析

深入Redis的RDB和AOF兩種持久化方式以及AOF重寫機制的分析

這裡寫圖片描述
快取伺服器有一個很重要的指標就是能否持久化,如果快取伺服器不支援持久化的話,一些相對重要的資料都不能存在快取伺服器中了,畢竟誰也不能保證服務百分百可用,一旦快取伺服器宕機,所有資料就都丟失了。

今天來分享一下Redis的持久化兩種持久化方式RDB和AOF。

1、RDB

RDB(redis database),可以理解為快照/記憶體快照,RDB持久化過程是將當前程序中的資料生成快照儲存到硬碟中。

1.1、觸發機制

RDB持久化的觸發機制分為兩種,手動觸發和自動觸發。

手動觸發

執行save和bgsave兩個命令可以手動觸發RDB持久化
- save命令會阻塞當前伺服器,直到RDB完成為止,如果資料量大的話會造成長時間的阻塞,線上環境一般禁止使用
- bgsave很好理解,就是background save,執行bgsave命令時Redis程序會fork一個子程序來完成RDB的過程,完成後自動結束,所以Redis主程序阻塞時間只有fork階段的那一下。相對於save,阻塞時間很短。

自動觸發

在redis.config配置檔案裡可以配置自動觸發,配置方式如下:

save <seconds> <changes>

這個配置的規則指的是在seconds秒內發生changes次寫操作,就會自動進行一次bgsave,例如:

save 900 1

指的是如果900秒內有1條Key資訊發生變化就會觸發一次bgsave。

還有在執行shutdown命令的時候,如果沒有開啟AOF持久化功能,那麼會自動執行一次bgsave。

1.2、RDB執行流程

  • 執行bgsave命令的時候,Redis主程序會檢查是否有子程序在執行RDB/AOF持久化任務,如果有的話,直接返回。
  • Redis主程序會fork一個子程序來執行執行RDB操作,fork操作會對主程序造成阻塞(影響Redis的讀寫),fork操作完成後會發訊息給主程序,從而不再阻塞主程序。
  • RDB子程序會根據Redis主程序的記憶體生成臨時的快照檔案,RDB完成後會使用臨時快照檔案替換掉原來的RDB檔案。
  • RDB子程序完成RDB持久化後會發訊息給主程序,通知RDB持久化完成。

上面講的是RDB持久化執行的主要流程,下面再講一些細節上的東西:
- 在有子程序執行RDB過程的時候,Redis主程序的讀寫不受影響,但是對於Redis的寫操作不會同步到主程序的主記憶體中,而是會寫到一個臨時的記憶體區域作為一個副本,等到主程序接收到子程序完成RDB過程的訊息後再將記憶體副本中的資料同步到主記憶體。
- Redis預設採用LZF演算法對RDB檔案進行壓縮,所以生成的記憶體檔案會比記憶體小很多。

1.3、RDB的優缺點

優點:
  • RDB檔案小,非常適用於定時備份,用於災難恢復。
  • Redis載入RDB檔案的速度比AOF快很多,因為RDB檔案中直接儲存的時記憶體資料,而AOF檔案中儲存的是一條條命令。
缺點:
  • RDB無法做到實時持久化,因為fork子程序屬於重量級操作,會阻塞Redis主程序。
  • 存在老版本的Redis不相容新版本RDB格式檔案的問題。

主要因為RDB持久化不支援實時持久化,只要Redis服務宕機了,那麼從上一次bgsave到宕機之間的所有資料都會丟失,所以在資料實時性要求高的情況下不適合使用RDB,所以Redis又提供了AOF持久化

2、AOF持久化

AOF(append only file),以日誌的方式記錄每次寫命令,服務重啟的時候重新執行AOF檔案中的命令來恢復記憶體資料。因為解決了資料持久化實時性的問題,所以目前AOF是Redis持久化的主流方式。

2.1、開啟AOF

AOF預設是關閉的,可以在redis.conf配置檔案中新增下面配置開啟AOF

appendonly yes

2.2、AOF執行流程

  • 所有的寫命令都會追加到aof_buf(緩衝區)中。
  • 可以使用不同的策略將AOF緩衝區中的命令寫到AOF檔案中。
  • 隨著AOF檔案的越來越大,會對AOF檔案進行重寫。
  • 當伺服器重啟的時候,會載入AOF檔案並執行AOF檔案中的命令用於恢復資料。

簡單分析一下AOF執行流程中的一些問題:
- 因為Redis為了效率,使用單執行緒來響應命令,如果每次寫命令都追加寫硬碟的操作,那麼Redis的響應速度還要取決於硬碟的IO效率,顯然不現實,所以Redis將寫命令先寫到AOF緩衝區。
- 寫道緩衝區還有一個好處是可以採用不同的策略來實現緩衝區到硬碟的同步,可以讓使用者自行在安全性和效能方面做出權衡。

2.3、同步策略

在瞭解同步策略之前,需要先來了解兩個三方法flushAppendOnlyFile、write和save:
- redis的伺服器程序是一個事件迴圈,檔案事件負責處理客戶端的命令請求,而時間事件負責執行serverCron函式這樣的定時執行的函式。在處理檔案事件執行寫命令,使得命令被追加到aof_buf中,然後在處理時間事件執行serverCron函式會呼叫flushAppendOnlyFile函式進行檔案的寫入和同步
- write:根據條件,將aof_buf中的快取寫入到AOF檔案
- save:根據條件,呼叫fsync或fdatasync函式將AOF檔案儲存到磁碟

下面來介紹Redis支援的三種同步策略:
- AOF_FSYNC_NO:不儲存(write和read命令都由主程序執行)
- AOF_FSYNC_EVERYSEC:每一秒鐘儲存一次(write由主程序完成,save由子程序完成)
- AOF_FSYNC_ALWAYS:每執行一個命令儲存一次(write和read命令都由主程序執行)

AOF_FSYNC_NO

在這種策略下,每次flushAppendOnlyFile函式被呼叫的時候都會執行一次write方法,但是不會執行save方法。

只有下面三種情況下才會執行save方法:
- Redis被關閉
- AOF功能被關閉
- 系統的寫快取被重新整理(可能是快取已經被寫滿,或者定期儲存操作被執行)

這三種情況下的save操作都會引起Redis主程序阻塞,並且由於長時間沒有執行save命令,所以save命令執行的時候,阻塞時間會很長

AOF_FSYNC_EVERYSEC

在這種策略下,save操作原則上每隔一秒鐘就會執行一次, 因為save操作是由後臺子執行緒呼叫的, 所以它不會引起伺服器主程序阻塞。

其實根據Redis的狀態,每當 flushAppendOnlyFile函式被呼叫時,write命令和save命令的執行又分為四種不同情況:

AOF everysec

根據以上圖知道,在AOF_FSYNC_EVERYSEC策略下, 如果在情況1時發生故障停機, 那麼使用者最多損失小於2秒內所產生的資料;而如果在情況2時發生故障停機,堆積了很多save命令,那麼使用者損失的資料是可以超過 2 秒的。

AOF_FSYNC_ALWAYS

在這種模式下,每次執行完一個命令之後,write和save命令都會被執行。

另外,因為save命令是由Redis主程序執行的,所以在save命令執行期間,主程序會被阻塞。

三種策略的優缺點

AOF_FSYNC_NO策略雖然表面上看起來提升了效能,但是會存在每次save命令執行的時候相對長時間阻塞主程序的問題。並且資料的安全性的不到保證,如果Redis伺服器突然宕機,那麼沒有從AOF快取中儲存到硬碟中的資料都會丟失。

AOF_FSYNC_ALWAYS策略的安全性的到了最大的保障,理論上最多丟失最後一次寫操作,但是由於每個寫操作都會阻塞主程序,所以Redis主程序的響應速度受到了很大的影響。

AOF_FSYNC_EVERYSEC策略是比較建議的配置,也是Redis的預設配置,相對來說兼顧安全性和效能。

2.4、重寫機制

隨著命令不斷從AOF快取中寫入到AOF檔案中,AOF檔案會越來越大,為了解決這個問題,Redis引入了AOF重寫機制來壓縮AOF檔案。

AOF檔案的壓縮和RDB檔案的壓縮原理不一樣,RDB檔案的壓縮是使用壓縮演算法將二進位制的RDB檔案壓縮,而AOF檔案的壓縮主要是去除AOF檔案中的無效命令,比如說:
- 同一個key的多次寫入只保留最後一個命令
- 已刪除、已過期的key的寫命令不再保留

AOF重寫的觸發機制也分為手動觸發和自動觸發兩種方式。

手動觸發

執行bgrewriteaof命令直接觸發AOF重寫

自動觸發

在redis.config配置檔案中有兩個配置項

auto-aof-rewrite-min-size 64MB
auto-aof-rewrite-min-percenrage 100

上面兩個配置表示:
- 當AOF檔案小於64MB的時候不進行AOF重寫
- 噹噹前AOF檔案比上次AOF重寫後的檔案大100%的時候進行AOF重寫

可以在redis.conf配置檔案中新增這兩個引數來自動觸發AOF重寫,執行bgrewriteaof命令

2.5、AOF重寫流程

  • 執行bgrewriteaof命令的時候,如果當前有程序正在執行AOF重寫,那麼直接返回;如果有程序正在執行bgsave,那麼等待bgsave執行完畢再執行AOF重寫。
  • Redis主程序會fork一個子程序執行AOF重寫,開銷和RDB重寫一樣。
  • AOF重寫過程中,不影響Redis原有的AOF過程,包括寫訊息到AOF快取以及同步AOF快取中的資料到硬碟。
  • AOF重寫過程中,主程序收到的寫操作還會將命令寫到AOF重寫緩衝區,注意和AOF緩衝區區分開。
  • 由於AOF重寫過程中原AOF檔案還在陸續寫入資料,所以AOF重寫子程序只會拿到fork子程序時的AOF檔案進行重寫。
  • 子程序拿到原AOF檔案中的資料寫道一個臨時的AOF檔案中。
  • 子程序完成AOF重寫後會發訊息給主程序,主程序會把AOF重寫緩衝區中的資料寫道AOF緩衝區,並且用新的AOF檔案替換舊的AOF檔案。

上面講的是AOF重寫的主要流程,下面再講一些細節上的東西:
- Redis對AOF的重要性看得比RDB重,因為RDB的時候如果有程序正在執行AOF,那麼直接返回;而AOF的時候如果有程序正在執行RDB,那麼等RDb結束再執行AOF。
- Redis再AOF重寫的時候新建一個AOF重寫緩衝區的目的是為了保證重寫過程中的寫命令資料不會丟失。
- 子程序在重寫AOF檔案的時候,每次寫硬碟的資料量由配置決定,不能太大,否則會導致硬碟阻塞(預設32MB)。
- AOF重寫的整個過程有三個部分會阻塞程序:
- 主程序fork子程序的時候
- 主程序把AOF重寫緩衝區中的資料寫到AOF緩衝區的時候
- 使用新的AOF檔案替換掉舊的AOF檔案的時候

3、Redis重啟時載入持久化檔案的順序

  • Redis重啟的時候優先載入AOF檔案,如果AOF檔案不存在再去載入RDB檔案。
  • 如果AOF檔案和RDB檔案都不存在,那麼直接啟動。
  • 不論載入AOF檔案還是RDB檔案,只要發生錯誤都會列印錯誤資訊,並且啟動失敗。

4、總結

關於Redis的兩種持久化方式到這裡就介紹完了,這裡再總結一下:
- RDB持久化基於記憶體快照儲存二進位制檔案,AOF持久化基於寫命令儲存文字檔案。
- RDB檔案採用了壓縮演算法,比較小;AOF檔案隨著命令的疊加會越來越大,Redis提供了AOF重寫來壓縮AOF檔案。
- 恢復RDB檔案的速度比AOF檔案快很多。
- RDB持久化方式實時性不好,所以AOF持久化更主流。
- 合理的使用AOF的同步策略,理論上不會丟失大量的資料。

·—

喜歡這篇文章的朋友,歡迎掃描下圖關注公眾號lebronchen,第一時間收到更新內容。
這裡寫圖片描述