深刻解讀 Redis 的持久化

Redis持久化

Java大猿帥成長手冊,GitHub JavaEgg ,N線互聯網開發必備技能兵器譜html

Redis 的數據所有在內存裏,若是忽然宕機,數據就會所有丟失,所以必須有一種機制來保證 Redis 的數據不會由於故障而丟失,這種機制就是 Redis 的持久化機制。git

Redis有兩種持久化的方式:快照(RDB文件)和追加式文件(AOF文件)github

RDB(Redis DataBase)

是什麼

在指定的時間間隔內將內存中的數據集快照寫入磁盤,也就是行話講的Snapshot快照,它恢復時是將快照文件直接讀到內存裏。redis

Redis會單首創建(fork)一個子進程來進行持久化,會先將數據寫入到一個臨時文件中,待持久化過程都結束了,再用這個臨時文件替換上次持久化好的文件。整個過程當中,主進程是不進行任何IO操做的,這就確保了極高的性能,若是須要進行大規模數據的恢復,且對於數據恢復的完整性不是很是敏感,那 RDB 方式要比 AOF 方式更加的高效。RDB的缺點是最後一次持久化後的數據可能丟失。數據庫

? What ? Redis 不是單進程的嗎?編程

Redis 使用操做系統的多進程 COW(Copy On Write) 機制來實現快照持久化, fork是類Unix操做系統上建立進程的主要方法。COW(Copy On Write)是計算機編程中使用的一種優化策略。緩存

Fork

fork 的做用是複製一個與當前進程同樣的進程。新進程的全部數據(變量、環境變量、程序計數器等)數值都和原進程一致,可是是一個全新的進程,並做爲原進程的子進程。 子進程讀取數據,而後序列化寫到磁盤中安全

rdb 默認保存的是dump.rdb文件服務器

你能夠對 Redis 進行設置, 讓它在「 N 秒內數據集至少有 M 個改動」這一條件被知足時, 自動保存一次數據集。app

你也能夠經過調用 SAVE 或者 BGSAVE , 手動讓 Redis 進行數據集保存操做。

好比說, 如下設置會讓 Redis 在知足「 60 秒內有至少有 1000 個鍵被改動」這一條件時, 自動保存一次數據集:

save 60 1000

這種持久化方式被稱爲快照(snapshot)。

配置位置: SNAPSHOTTING

redis-snapshotting.png

如何觸發RDB快照

  • 配置文件中默認的快照配置

    冷拷貝後從新使用 能夠cp dump.rdb dump_new.rdb

  • 命令save或者是bgsave

    • Save:save時只管保存,其它無論,所有阻塞
    • BGSAVE:Redis會在後臺異步進行快照操做,快照同時還能夠響應客戶端請求。能夠經過lastsave命令獲取最後一次成功執行快照的時間
    • 執行flushall命令,也會產生dump.rdb文件,但裏面是空的,無心義

快照的運做方式

當 Redis 須要保存 dump.rdb 文件時, 服務器執行如下操做:

  1. Redis 調用 fork() ,產生一個子進程,此時同時擁有父進程和子進程。
  2. 子進程將數據集寫入到一個臨時 RDB 文件中。
  3. 當子進程完成對新 RDB 文件的寫入時,Redis 用新 RDB 文件替換原來的 RDB 文件,並刪除舊的 RDB 文件。

這種工做方式使得 Redis 能夠從寫時複製(copy-on-write)機制中獲益。

如何恢復

將備份文件 (dump.rdb) 移動到 redis 安裝目錄並啓動服務便可(CONFIG GET dir獲取目錄)

優點

  • 一旦採用該方式,那麼你的整個Redis數據庫將只包含一個文件,這對於文件備份而言是很是完美的。好比,你可能打算每一個小時歸檔一次最近24小時的數據,同時還要天天歸檔一次最近30天的數據。經過這樣的備份策略,一旦系統出現災難性故障,咱們能夠很是容易的進行恢復。適合大規模的數據恢復
  • 對於災難恢復而言,RDB是很是不錯的選擇。由於咱們能夠很是輕鬆的將一個單獨的文件壓縮後再轉移到其它存儲介質上。
  • 性能最大化。對於Redis的服務進程而言,在開始持久化時,它惟一須要作的只是fork出子進程,以後再由子進程完成這些持久化的工做,這樣就能夠極大的避免服務進程執行IO操做了。
  • 相比於AOF機制,若是數據集很大,RDB的啓動效率會更高。

劣勢

  • 若是你想保證數據的高可用性,即最大限度的避免數據丟失,那麼RDB將不是一個很好的選擇。由於系統一旦在定時持久化以前出現宕機現象,此前沒有來得及寫入磁盤的數據都將丟失(丟失最後一次快照後的全部修改)。
  • 因爲RDB是經過fork子進程來協助完成數據持久化工做的,內存中的數據被克隆了一份,大體2倍的膨脹性須要考慮,所以,若是當數據集較大時,可能會致使整個服務器中止服務幾百毫秒,甚至是1秒鐘。

如何中止

動態中止RDB保存規則的方法:redis-cli config set save ""

總結

redis-rdb.png

  • RDB是一個很是緊湊的文件

  • RDB在保存RDB文件時父進程惟一須要作的就是fork出一個子進程,接下來的工做所有由子進程來作,父進程不須要再作其餘IO操做,因此RDB持久化方式能夠最大化redis的性能

  • 與AOF相比,在恢復大的數據集的時候,RDB方式會更快一些

  • 數據丟失風險大

  • RDB須要常常fork子進程來保存數據集到硬盤上,當數據集比較大的時候,fork的過程是很是耗時的,可能會致使redis在一些毫秒級不能響應客戶端的請求

AOF(Append Only File)

是什麼

以日誌的形式來記錄每一個寫操做,將 Redis 執行過的全部寫指令記錄下來(讀操做不記錄),只許追加文件但不能夠改寫文件,redis 啓動之初會讀取該文件從新構建數據,也就是「重放」。換言之,redis 重啓的話就根據日誌文件的內容將寫指令從前到後執行一次以完成數據的恢復工做。

AOF 默認保存的是 appendonly.aof 文件

配置位置: APPEND ONLY MODE

redis-aof-conf.jpg

AOF啓動/修復/恢復

  • 正常恢復

    • 啓動:設置Yes 修改默認的appendonly no,改成yes
    • 將有數據的 aof 文件複製一份保存到對應目錄(config get dir)
    • 恢復:重啓redis而後從新加載
  • 異常恢復

    • 啓動:設置Yes 修改默認的appendonly no,改成yes
    • 備份被寫壞的AOF文件
    • 修復:redis-check-aof --fix進行修復 + AOF文件
    • 恢復:重啓redis而後從新加載

rewrite(AOF 重寫)

  • 是什麼:AOF採用文件追加方式,文件會愈來愈大爲避免出現此種狀況,新增了重寫機制,當 AOF 文件的大小超過所設定的閾值時,Redis就會啓動 AOF 文件的內容壓縮,只保留能夠恢復數據的最小指令集,可使用命令bgrewriteaof
  • 重寫原理:AOF 文件持續增加而過大時,會 fork 出一條新進程來將文件重寫(也是先寫臨時文件最後再rename),遍歷新進程的內存中數據,每條記錄有一條的 Set 語句。重寫 aof 文件的操做,並無讀取舊的aof文件,而是將整個內存中的數據庫內容用命令的方式重寫了一個新的 aof 文件,這點和快照有點相似
  • 觸發機制:Redis 會記錄上次重寫時的 AOF 大小,默認配置是當 AOF 文件大小是上次 rewrite 後大小的一倍且文件大於64M 時觸發

AOF耐久性

你能夠配置 Redis 多久纔將數據 fsync 到磁盤一次。

有三個選項:

  • 每次有新命令追加到 AOF 文件時就執行一次 fsync :很是慢,也很是安全。
  • 每秒 fsync 一次:足夠快(和使用 RDB 持久化差很少),而且在故障時只會丟失 1 秒鐘的數據。
  • 從不 fsync :將數據交給操做系統來處理。更快,也更不安全的選擇。

推薦(而且也是默認)的措施爲每秒 fsync 一次, 這種 fsync 策略能夠兼顧速度和安全性。

老是 fsync 的策略在實際使用中很是慢,頻繁調用 fsync 註定了這種策略不可能快得起來。

若是 AOF 文件出錯了,怎麼辦?

服務器可能在程序正在對 AOF 文件進行寫入時停機, 若是停機形成了 AOF 文件出錯(corrupt), 那麼 Redis 在重啓時會拒絕載入這個 AOF 文件, 從而確保數據的一致性不會被破壞。

當發生這種狀況時, 能夠用如下方法來修復出錯的 AOF 文件:

  1. 爲現有的 AOF 文件建立一個備份。
  2. 使用 Redis 附帶的 redis-check-aof 程序,對原來的 AOF 文件進行修復。

$ redis-check-aof --fix

  1. (可選)使用 diff -u 對比修復後的 AOF 文件和原始 AOF 文件的備份,查看兩個文件之間的不一樣之處。
  2. 重啓 Redis 服務器,等待服務器載入修復後的 AOF 文件,並進行數據恢復。

AOF運做方式

AOF 重寫和 RDB 建立快照同樣,都巧妙地利用了寫時複製機制。

如下是 AOF 重寫的執行步驟:

  1. Redis 執行 fork() ,如今同時擁有父進程和子進程。
  2. 子進程開始將新 AOF 文件的內容寫入到臨時文件。
  3. 對於全部新執行的寫入命令,父進程一邊將它們累積到一個內存緩存中,一邊將這些改動追加到現有 AOF 文件的末尾: 這樣即便在重寫的中途發生停機,現有的 AOF 文件也仍是安全的。
  4. 當子進程完成重寫工做時,它給父進程發送一個信號,父進程在接收到信號以後,將內存緩存中的全部數據追加到新 AOF 文件的末尾。
  5. 搞定!如今 Redis 原子地用新文件替換舊文件,以後全部命令都會直接追加到新 AOF 文件的末尾。

優點

  • 該機制能夠帶來更高的數據安全性,即數據持久性。Redis中提供了3種同步策略,即每秒同步、每修改同步和不一樣步。事實上,每秒同步也是異步完成的,其效率也是很是高的,所差的是一旦系統出現宕機現象,那麼這一秒鐘以內修改的數據將會丟失。而每修改同步,咱們能夠將其視爲同步持久化,即每次發生的數據變化都會被當即記錄到磁盤中。能夠預見,這種方式在效率上是最低的。至於無同步,無需多言,我想你們都能正確的理解它。
  • 因爲該機制對日誌文件的寫入操做採用的是append模式,所以在寫入過程當中即便出現宕機現象,也不會破壞日誌文件中已經存在的內容。然而若是咱們本次操做只是寫入了一半數據就出現了系統崩潰問題,不用擔憂,在Redis下一次啓動以前,咱們能夠經過redis-check-aof工具來幫助咱們解決數據一致性的問題。
  • 若是日誌過大,Redis能夠自動啓用rewrite機制。即Redis以append模式不斷的將修改數據寫入到老的磁盤文件中,同時Redis還會建立一個新的文件用於記錄此期間有哪些修改命令被執行。所以在進行rewrite切換時能夠更好的保證數據安全性。
  • AOF 包含一個格式清晰、易於理解的日誌文件用於記錄全部的修改操做。事實上,咱們也能夠經過該文件完成數據的重建。所以 AOF 文件的內容很是容易被人讀懂, 對文件進行分析(parse)也很輕鬆。 導出(export) AOF 文件也很是簡單: 舉個例子, 若是你不當心執行了 FLUSHALL 命令, 但只要 AOF 文件未被重寫, 那麼只要中止服務器, 移除 AOF 文件末尾的 FLUSHALL 命令, 並重啓 Redis , 就能夠將數據集恢復到 FLUSHALL 執行以前的狀態。

劣勢

  • 對於相同數量的數據集而言,AOF文件一般要大於RDB文件。恢復速度慢於rdb。
  • 根據同步策略的不一樣,AOF在運行效率上每每會慢於RDB。總之,每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB同樣高效。

總結

redis-aof.png

  • AOF 文件是一個只進行追加的日誌文件
  • Redis 能夠在 AOF 文件體積變得過大時,自動在後臺對 AOF 進行重寫
  • AOF文件有序的保存了對數據庫執行的全部寫入操做,這些寫入操做以Redis協議的格式保存,所以AOF文件的內容很是容易被人讀懂,對文件進行分析也很輕鬆
  • 對於相同的數據集來講,AOF 文件的體積一般須要大於 RDB 文件的體積
  • 根據所使用的 fsync 策略,AOF 的速度可能會慢於 RDB

怎麼從 RDB 持久化切換到 AOF 持久化

在 Redis 2.2 或以上版本,能夠在不重啓的狀況下,從 RDB 切換到 AOF :

  1. 爲最新的 dump.rdb 文件建立一個備份。
  2. 將備份放到一個安全的地方。
  3. 執行如下兩條命令:
redis-cli> CONFIG SET appendonly yes   

 redis-cli> CONFIG SET save ""
  1. 確保命令執行以後,數據庫的鍵的數量沒有改變。
  2. 確保寫命令會被正確地追加到 AOF 文件的末尾。

步驟 3 執行的第一條命令開啓了 AOF 功能: Redis 會阻塞直到初始 AOF 文件建立完成爲止, 以後 Redis 會繼續處理命令請求, 並開始將寫入命令追加到 AOF 文件末尾。

步驟 3 執行的第二條命令用於關閉 RDB 功能。 這一步是可選的, 若是你願意的話, 也能夠同時使用 RDB 和 AOF 這兩種持久化功能。

別忘了在 redis.conf 中打開 AOF 功能! 不然的話, 服務器重啓以後, 以前經過 CONFIG SET 設置的配置就會被遺忘, 程序會按原來的配置來啓動服務器。

Which one

  • RDB 持久化方式可以在指定的時間間隔能對你的數據進行快照存儲

  • AOF 持久化方式記錄每次對服務器寫的操做,當服務器重啓的時候會從新執行這些命令來恢復原始的數據,AOF命令以 redis 協議追加保存每次寫的操做到文件末尾。Redis還能對AOF文件進行後臺重寫(bgrewriteaof),使得 AOF 文件的體積不至於過大

  • 只作緩存:若是你只但願你的數據在服務器運行的時候存在,你也能夠不使用任何持久化方式。

  • 同時開啓兩種持久化方式

    • 在這種狀況下,當 redis 重啓的時候會優先載入 AOF 文件來恢復原始的數據,由於在一般狀況下 AOF 文件保存的數據集要比 RDB 文件保存的數據集要完整。
    • RDB 的數據不實時,同時使用二者時服務器重啓也只會找 AOF 文件。那要不要只使用AOF 呢?建議不要,由於 RDB 更適合用於備份數據庫(AOF 在不斷變化很差備份),快速重啓,並且不會有 AOF 可能潛在的bug,留着做爲一個萬一的手段。

性能建議

  • 由於 RDB 文件只用做後備用途,建議只在 Slave上持久化 RDB 文件,並且只要15分鐘備份一次就夠了,只保留save 900 1這條規則。
  • 若是Enalbe AOF,好處是在最惡劣狀況下也只會丟失不超過兩秒數據,啓動腳本較簡單隻load本身的 AOF 文件就能夠了。代價一是帶來了持續的 IO,二是 AOF rewrite 的最後將 rewrite 過程當中產生的新數據寫到新文件形成的阻塞幾乎是不可避免的。只要硬盤許可,應該儘可能減小 AOF rewrite 的頻率,AOF 重寫的基礎大小默認值64M過小了,能夠設到5G以上。默認超過原大小100%大小時重寫能夠改到適當的數值。
  • 若是不 Enable AOF ,僅靠 Master-Slave Replication 實現高可用性也能夠。能省掉一大筆 IO ,也減小了rewrite 時帶來的系統波動。代價是若是 Master/Slav e同時宕掉,會丟失十幾分鐘的數據,啓動腳本也要比較兩個Master/Slave中的RDB文件,載入較新的那個。

Redis Persistence

某免費教學視頻

相關文章
相關標籤/搜索