Redis之RDB和AOF持久化介紹

什麼是數據庫狀態redis

  redis是一個鍵值對的數據庫服務器,服務器中一般包含中任意個非空的數據庫,而每一個數據庫又能夠包含任意個鍵值對,爲了方便起見,咱們將服務器中的非空數據庫以及他們的鍵值對統稱爲數據庫狀態。數據庫

RDB持久化的邏輯數組

  RDB持久化就能夠手動執行也能夠根據服務器配置選項按期的執行,該功能能夠將某個時間點上的數據庫狀態保存到一個RDB文件中,這個文件實際上是一個二進制的文件,經過這個文件能夠還原生成RDB文件時的數據庫狀態。安全

RDB文件的建立服務器

  有兩個生成redisRDB文件的命令,一個是SAVE,一個是BGSAVE。SAVE命令是使用服務器進程來生成RDB文件,在生成RDB文件的時候,會阻塞全部的讀寫操做,服務器不能處理任何命令請求。BGSAVE命令是同過服務器進程派生出來一個子進程,而後有子進程負責建立RBD文件,服務器進程能夠繼續處理命令請求。併發

  其實建立RDB文件的工做都是經過rdbsave函數實現的是不過兩種命令以不一樣的方式調用這個函數。app

SAVE命令執行時的服務器狀態函數

  其實這個很簡單,咱們上面已經提到過SAVE命令或阻塞一切請求,固然擁抱口BGSAVE請求了,因此在執行SAVE期間,再次執行BGSAVE命令會被直接拒絕工具

BGSAVE命令執行時的服務器狀態性能

  咱們知道BGSAVE命令是服務器的子進程來完成的,服務器進程能夠繼續接收和執行命令,可是再BGSAVE命令執行期間服務器處理SAVE、BGSAVE、BGREWRITEAOF三個命令的方式和平時有所不一樣,主要有一下幾種情形:

  1.在BGSAVE命令執行期間,客戶端發起的SAVE命令會被服務器拒絕。服務器禁止SAVE命令和BGDAVE命令同時執行是爲了不父進程和子進程同時執行兩個rdbsave調用,防止產生競爭條件。

  2.在BGSAVE命令執行期間客戶端發起BGSAVE命令會被服務器拒絕,由於同時執行兩個BGSAVE命令也會產生競爭條件

  3.在BGSAVE命令執行期間,客戶端發起BGREWRITEAOF命令會被延遲到BGSAVE命令執行完畢以後執行

  4.在BGREWRITEAOF命令執行期間,客戶端發起BGSAVE命令會被服務器直接拒絕,主要是由於BGREWRITEAOF和BGSAVE命令都是由子進程來完成的,禁止他們同時執行知識一個性能方面的考慮,由於併發出兩個子進程,而且這兩個子進程同時進行大量的磁盤寫入操做,並非什麼好事情。

RDB文件的載入

  對於RDB文件的載入就相對簡單了,RDB文件的載入工做是在服務器啓動的時候自動執行的,而且在服務器載入RDB文件期間,會一直處於阻塞狀態,直到載入工做完成爲止。

RDB自動間歇性保存

  上面咱們講了如何建立RDB文件,可是何時來建立RBD文件呢?除了手動的執行命令以外,咱們還能夠經過配置來讓服務器自動來建立RDB文件,咱們能夠在redis的配置文件中經過如下配置來實現:

save    900    1 save 300    10 save 60     10000

  用戶能夠經過save選項設置多個保存條件(固然能夠超過三個了,十個八個均可以,由於這些保存條件實際上是保存在一個數組中的),可是隻要其實任意一個條件知足,服務器就會執行BGSAVE命令。而上面的三條保存配置其實也是在咱們開啓了RDB持久化可是沒有配置相關保存條件下時服務器給的默認的配置。

RDB自動保存的觸發原理

  咱們知道了如何配置保存條件的,可是這個保存條件是怎麼觸發的呢?

  其實服務器除了經過一個數據存儲咱們的保存條件外,還會維持一個dirty的計數器,以及一個lastsave屬性,其中dirty計數器用來統計距離上一次成功執行SAVE命令或者BGSAVE命令後服務器對數據庫狀態進行了多少次修改(包括寫入,刪除,更新等操做),而lastsave屬性是一個UNIX的時間戳,記錄了服務器上一次成功執行SAVE命令或者BGSAVE命令的時間。這兩個值都會在成功執行完BGSAVE命令後重置:dirty重置成0,lastsave更新爲當前時間。

  而對於條件的判斷則是Redis服務器會週期性的操做函數serverCron默認每隔100毫秒執行一次,該函數用於對正在運行的服務器進行維護,它的其中一項工做就是檢查save選項所設置的保存條件是否知足,若是知足則執行BGSAVe命令。必須同時知足的條件是:1.距離上一次成功執行保存的時間超過設置的時間,2.數據庫狀態的修改次數超過設置的修改次數

RDB的文件結構

暫略

 AOF持久化的邏輯

  與RBD持久化經過保存數據庫中的鍵值對來記錄數據庫狀態不一樣,AOF持久化是經過保存redis服務器所執行的寫命令來記錄數據庫狀態的。

  被寫入到AOF文件的命令都是以Redis的命令請求協議格式保存的,由於Redis的命令請求協議是純文本的,因此咱們能夠直接打開一個AOF文件,裏面保存的基本都是咱們執行的命令,可是會有一些SELECT命令,SELECT命令是用於指定數據庫的,此命令是服務器自動添加的。

AOF持久化的過程

  AOF持久化過程的實現能夠分爲命令追加、文件寫入、文件同步三個步驟。

  命令追加:當AOF功能打開的時候,服務器執行一條命令以後,會以協議格式將被執行的寫命令追加到服務器狀態的aof_buf緩衝區的額末尾,可是aof_buf緩衝區的命令何時寫入aof文件這個要根據額咱們的appendfsync的相關配置來決定

  文件寫入和同步:爲了提升文件的寫入效率,在現代的操做系統中,當用戶調用write函數,將一些數據寫入到文件的時候,操做系統一般會將寫入數據暫時存放到一個內存緩衝區裏面,等到緩衝區滿了或者超過了執行的時限以後,才真正的將緩衝區中的數據寫入到磁盤裏面

  咱們須要注意的是,Redis的服務器進程就是一個事件循環,這個循環中的文件時間負責接收客戶端的命令請求,以及向客戶端發送命令回覆,而時間時間則負責執行向serverCron函數這樣的須要定時運行的函數

  由於服務器在處理文件事件時可能會執行寫命令,使得這些內容被追加到aof_buf緩衝區裏面,因此在服務器每次結束一個時間循環以前,它都會調用flushAppendOnlyFile函數,考慮是否須要將aof_buf緩衝區中的內容寫入和保存到AOF文件裏面。

  flushAppendOnlyFile函數的行爲是有服務器配置文件的appendfsync選項的值來決定的,appendfsync的值有三種:

  1.always:將aof_buf緩衝區中的數據寫入並同步到AOF文件。這種設置時最安全的,就變機器出現故障,也只是會丟失一個事件循環中所產生的命令數據

  2.everysec:將aof_buf緩衝區的全部內容寫入到AOF文件,若是上次同步AOF文件的時間距離如今超過1s,那麼再次對AOF文件進行同步,而且這個同步操做有一個線程專門完成。這種設置,服務器在每一個事件循環中都要將aof_buf緩衝區中的全部內容寫入到Aof文件,而且每隔1s就要在子線程中對AOF文件進行一次同步。從效率上來說everysec模式足夠快,而且就算出現故障停機,數據庫也只丟失一秒鐘的命令數據。

  3.no:在服務器的每一個事件循環鍾都要將aof緩衝區中的全部內容寫入到AOF文件,但不對AOF文件進行同步,什麼時候同步有操做系統來同步,因此這種設置是若是服務器停機,將會丟掉上次AOF文件同步後的全部寫命令數據。

AOF文件的載入和數據還原

  由於AOF文件中包含了重建數據庫狀態所需的全部寫命令,因此服務器只要讀入並從新執行一邊AOF文件裏面保存的寫命令,就能夠還原服務器關閉以前的數據狀態。
AOF重寫
   由於Aof持久化是經過保存被執行的寫命令來記錄數據庫狀態的,因此隨着服務器事件的流逝,AOF文件內容會愈來愈大,文件體積也會也來越大,若是不加控制體積過大的AOF文件極可能對Redis服務器甚至宿主機形成影響。對於數據恢復來講,AOF文件中會有不少冗餘的命令,好比對某個key操做了八次,AOF文件中會記錄八條寫命令,可是咱們關心的只是最後一次命令執行後的數據狀態,爲了解決AOF文件體積膨脹問題,Redis提供了AOF重寫功能。

  AOF重寫沒有對進行AOF任何操做,只是對AOF重寫時候的數據狀態轉成寫命令保存起來,也就是說重寫後的AOF文件中保存着可以換膚重寫時數據庫狀態的最小的寫命令數,這樣就能夠大大的減小文件的體積了。

  須要注意的是在重寫程序中在處理列表、哈希表、集合、有序集合這四種可能會帶來多個元素的鍵時,會先檢查包含元素的數量,若是數量超過了設置的常量值(這個值不通版本是不同的),就會用多條命令來記錄這個鍵而不僅僅時一條命令。

  由於Reids是單線程的,爲了避免是AOF重寫時阻塞服務器的正常運行,redis決定將AOF重寫放到一個子進程中進行,這樣作有兩個好處:

    1.子進程進行AOF重寫期間,服務器進程(父進程)能夠繼續處理命令請求

    2.子進程帶有服務器進程的數據副本,使用子進程而不是線程,能夠在避免使用所得狀況下,保證數據得安全性

  有個問題咱們要注意,在子進程AOF重寫期間,服務器進程還須要繼續處理命令請求,這個時候redis用來一個AOF重寫緩衝區來解決這個問題,也就是說,在子進程AOF重寫期間,服務器進程會進行三個工做:

    1.執行客戶端發來得命令

    2.將執行後得寫命令追加得AOF緩衝區

    3.將執行後得寫命令追加得AOF重寫緩衝區

  這樣一來能夠保證:

    1.AOF緩衝區得內容會按期被寫入和同步到AOF文件,對如今AOF文件得處理工做會如常進行

    2.從建立子進程開始,服務器得全部寫命令都會被記錄到AOF重寫緩衝區裏面

  當子進程完成AOF重寫後,會向服務器進程發一個信號,並調用一個信號處理函數執行一下工做:

    1.將Aof重寫緩衝區中得全部內容寫入到新得Aof文件中,這是新AOF文件所保存得數據庫狀態將和服務器當前得數據庫狀態保持一致

    2.對新的AOF文件進行更名,原子的覆蓋如今的AOF文件,完成新舊文件的交替

  在整個AOF後臺重寫過程當中,只有信號處理的時候會對服務器進程(父進程)形成阻塞,其餘時候AOF後臺重寫都不會阻塞父進程,這將AOF重寫對服務器形成的影響講到了最低。

RDB持久化和AOF持久化的對比

RDB優劣勢
優點:

  • RDB只表明某個時間點上的數據快照,因此適用於備份與全量複製,如一天進行備份一次。
  • Redis再加載RDB文件恢復數據遠快於AOF文件
  • 性能上考慮RDB優於AOF,由於咱們保存RDB文件只需fork一次子進程進行保存操做,父進程沒有對磁盤I/O

劣勢:

  • RDB沒辦法作到實時的持久化數據,由於fork是重量級別的操做,頻繁執行成本太高
  • RDB須要常常fork子進程來保存數據集到磁盤,當數據集比較大額時候,fork的過程是比較耗時的,可能會致使redis在一些毫秒級不能響應客服端請求
  • 老版本的Redis沒法兼容新版本的RDB文件

AOF優劣勢
優點:

  • 經過配置同步策略基本可以達到實時持久化數據,如配置爲everysec,則每秒同步一次AOF文件,也就是說最多丟失一秒鐘的數據,兼顧了性能與數據的安全性
  • AOF 文件是一個只進行追加操做的日誌文件(append only log), 所以對 AOF 文件的寫入不須要進行 seek , 即便日誌由於某些緣由而包含了未寫入完整的命令(好比寫入時磁盤已滿,寫入中途停機,等等), redis-check-aof 工具也能夠輕易地修復這種問題。

劣勢:

    • 對於相同的數據集來講,AOF 文件的體積一般要大於 RDB 文件的體積。
    • 與AOF相比,在恢復大的數據時候,RDB方式更快一些
相關文章
相關標籤/搜索