RBD和AOF持久化對比

RDB和AOF持久化對比

Redis提供了RDB持久化和AOF持久化,本篇文章中將會對這兩種機制進行一些對比javascript

RDB機制的優點和略施

RDB持久化是指在指定的時間間隔內將內存中的數據集快照寫入磁盤。 也是默認的持久化方式,這種方式是就是將內存中數據以快照的方式寫入到二進制文件中,默認的文件名爲dump.rdb。java

能夠經過配置設置自動作快照持久化的方式。咱們能夠配置redis在n秒內若是超過m個key被修改就自動作快照,下面是默認的快照保存配置redis

save 900 1  #900秒內若是超過1個key被修改,則發起快照保存
   save 300 10 #300秒內容如超過10個key被修改,則發起快照保存
   save 60 10000

RDB文件保存過程

  • redis調用fork,如今有了子進程和父進程。
  • 父進程繼續處理client請求,子進程負責將內存內容寫入到臨時文件。因爲os的寫時複製機制(copy on write)父子進程會共享相同的物理頁面,當父進程處理寫請求時os會爲父進程要修改的頁面建立副本,而不是寫共享的頁面。因此子進程的地址空間內的數 據是fork時刻整個數據庫的一個快照。
  • 當子進程將快照寫入臨時文件完畢後,用臨時文件替換原來的快照文件,而後子進程退出。

client 也可使用save或者bgsave命令通知redis作一次快照持久化。save操做是在主線程中保存快照的,因爲redis是用一個主線程來處理全部 client的請求,這種方式會阻塞全部client請求。因此不推薦使用。數據庫

另外一點須要注意的是,每次快照持久化都是將內存數據完整寫入到磁盤一次,並不 是增量的只同步髒數據。若是數據量大的話,並且寫操做比較多,必然會引發大量的磁盤io操做,可能會嚴重影響性能。緩存

優點

  • 一旦採用該方式,那麼你的整個Redis數據庫將只包含一個文件,這樣很是方便進行備份。好比你可能打算沒1天歸檔一些數據。
  • 方便備份,咱們能夠很容易的將一個一個RDB文件移動到其餘的存儲介質上
  • RDB 在恢復大數據集時的速度比 AOF 的恢復速度要快。
  • RDB 能夠最大化 Redis 的性能:父進程在保存 RDB 文件時惟一要作的就是 fork 出一個子進程,而後這個子進程就會處理接下來的全部保存工做,父進程無須執行任何磁盤 I/O 操做。

劣勢

  • 若是你須要儘可能避免在服務器故障時丟失數據,那麼 RDB 不適合你。 雖然 Redis 容許你設置不一樣的保存點(save point)來控制保存 RDB 文件的頻率, 可是, 由於RDB 文件須要保存整個數據集的狀態, 因此它並非一個輕鬆的操做。 所以你可能會至少 5 分鐘才保存一次 RDB 文件。 在這種狀況下, 一旦發生故障停機, 你就可能會丟失好幾分鐘的數據。
  • 每次保存 RDB 的時候,Redis 都要 fork() 出一個子進程,並由子進程來進行實際的持久化工做。 在數據集比較龐大時, fork() 可能會很是耗時,形成服務器在某某毫秒內中止處理客戶端; 若是數據集很是巨大,而且 CPU 時間很是緊張的話,那麼這種中止時間甚至可能會長達整整一秒。 雖然 AOF 重寫也須要進行 fork() ,但不管 AOF 重寫的執行間隔有多長,數據的耐久性都不會有任何損失。

AOF文件保存過程

redis會將每個收到的寫命令都經過write函數追加到文件中(默認是 appendonly.aof)。安全

當redis重啓時會經過從新執行文件中保存的寫命令來在內存中重建整個數據庫的內容。固然因爲os會在內核中緩存 write作的修改,因此可能不是當即寫到磁盤上。這樣aof方式的持久化也仍是有可能會丟失部分修改。不過咱們能夠經過配置文件告訴redis咱們想要 經過fsync函數強制os寫入到磁盤的時機。有三種方式以下(默認是:每秒fsync一次)服務器

appendonly yes              //啓用aof持久化方式
# appendfsync always      //每次收到寫命令就當即強制寫入磁盤,最慢的,可是保證徹底的持久化,不推薦使用
appendfsync everysec     //每秒鐘強制寫入磁盤一次,在性能和持久化方面作了很好的折中,推薦
# appendfsync no    //徹底依賴os,性能最好,持久化沒保證

aof 的方式也同時帶來了另外一個問題。持久化文件會變的愈來愈大。例如咱們調用incr test命令100次,文件中必須保存所有的100條命令,其實有99條都是多餘的。由於要恢復數據庫的狀態其實文件中保存一條set test 100就夠了。app

爲了壓縮aof的持久化文件。redis提供了bgrewriteaof命令。收到此命令redis將使用與快照相似的方式將內存中的數據 以命令的方式保存到臨時文件中,最後替換原來的文件。具體過程以下函數

  • redis調用fork ,如今有父子兩個進程
  • 子進程根據內存中的數據庫快照,往臨時文件中寫入重建數據庫狀態的命令
  • 父進程繼續處理client請求,除了把寫命令寫入到原來的aof文件中。同時把收到的寫命令緩存起來。這樣就能保證若是子進程重寫失敗的話並不會出問題。
  • 當子進程把快照內容寫入已命令方式寫到臨時文件中後,子進程發信號通知父進程。而後父進程把緩存的寫命令也寫入到臨時文件。
  • 如今父進程可使用臨時文件替換老的aof文件,並重命名,後面收到的寫命令也開始往新的aof文件中追加。

須要注意到是重寫aof文件的操做,並無讀取舊的aof文件,而是將整個內存中的數據庫內容用命令的方式重寫了一個新的aof文件,這點和快照有點相似。工具

優點

  • 使用 AOF 持久化會讓 Redis 變得很是耐久(much more durable):你能夠設置不一樣的 fsync 策略,好比無 fsync ,每秒鐘一次 fsync ,或者每次執行寫入命令時 fsync 。 AOF 的默認策略爲每秒鐘 fsync 一次,在這種配置下,Redis 仍然能夠保持良好的性能,而且就算髮生故障停機,也最多隻會丟失一秒鐘的數據( fsync 會在後臺線程執行,因此主線程能夠繼續努力地處理命令請求)。

  • AOF 文件是一個只進行追加操做的日誌文件(append only log), 所以對 AOF 文件的寫入不須要進行 seek , 即便日誌由於某些緣由而包含了未寫入完整的命令(好比寫入時磁盤已滿,寫入中途停機,等等), redis-check-aof 工具也能夠輕易地修復這種問題。
    Redis 能夠在 AOF 文件體積變得過大時,自動地在後臺對 AOF 進行重寫: 重寫後的新 AOF 文件包含了恢復當前數據集所需的最小命令集合。 整個重寫操做是絕對安全的,由於 Redis 在建立新 AOF 文件的過程當中,會繼續將命令追加到現有的 AOF 文件裏面,即便重寫過程當中發生停機,現有的 AOF 文件也不會丟失。 而一旦新 AOF 文件建立完畢,Redis 就會從舊 AOF 文件切換到新 AOF 文件,並開始對新 AOF 文件進行追加操做。

  • AOF 文件有序地保存了對數據庫執行的全部寫入操做, 這些寫入操做以 Redis 協議的格式保存, 所以 AOF 文件的內容很是容易被人讀懂, 對文件進行分析(parse)也很輕鬆。 導出(export) AOF 文件也很是簡單: 舉個例子, 若是你不當心執行了 FLUSHALL 命令, 但只要 AOF 文件未被重寫, 那麼只要中止服務器, 移除 AOF 文件末尾的 FLUSHALL 命令, 並重啓 Redis , 就能夠將數據集恢復到 FLUSHALL 執行以前的狀態。

劣勢

  • 對於相同的數據集來講,AOF 文件的體積一般要大於 RDB 文件的體積。

  • 根據所使用的 fsync 策略,AOF 的速度可能會慢於 RDB 。 在通常狀況下, 每秒 fsync 的性能依然很是高, 而關閉 fsync 可讓 AOF 的速度和 RDB 同樣快, 即便在高負荷之下也是如此。 不過在處理巨大的寫入載入時,RDB 能夠提供更有保證的最大延遲時間(latency)。

  • AOF 在過去曾經發生過這樣的 bug : 由於個別命令的緣由,致使 AOF 文件在從新載入時,沒法將數據集恢復成保存時的原樣。 (舉個例子,阻塞命令 BRPOPLPUSH 就曾經引發過這樣的 bug 。) 測試套件裏爲這種狀況添加了測試: 它們會自動生成隨機的、複雜的數據集, 並經過從新載入這些數據來確保一切正常。 雖然這種 bug 在 AOF 文件中並不常見, 可是對比來講, RDB 幾乎是不可能出現這種 bug 的。

抉擇

通常來講, 若是想達到足以媲美 PostgreSQL 的數據安全性, 你應該同時使用兩種持久化功能。

若是你很是關心你的數據, 但仍然能夠承受數分鐘之內的數據丟失, 那麼你能夠只使用 RDB 持久化。

其他狀況我我的喜愛選擇AOF

相關文章
相關標籤/搜索