Redis持久化機制詳解

Redis持久化機制詳解

一. 持久化的意義

  1. Redis持久化的意義:主要在於故障恢復。Redis如果僅將數據完全保存在內存中,是無法應對災難性故障的。如果Redis進程突然掛掉,保存在內存中的數據就全沒了,如果沒有持久化,後果不堪設想。使用持久化+定期備份(如備份到雲存儲上)的機制,可以在很大程度上解決Redis故障恢復的問題。這樣即使Redis服務宕機,且磁盤損壞,也可以從雲存儲上拉取備份的數據進行恢復,不會造成數據的全部丟失。
  2. 從一定意義上來說,Redis的持久化也可以視爲高可用的一部分。因爲如果沒有持久化和數據恢復,一旦Redis宕機,即使重啓,數據也都沒了,這樣大量的請求過來,由於沒有命中緩衝,就會直接打到MySQL上,造成緩存雪崩,這樣一來MySQL很有可能就掛了,整個系統就癱瘓了。如果持久化方案做的很好,即使Redis宕機,也可以快速重啓並恢復數據,重新回到可用狀態。

二. 持久化方式

  1. Redis持久化方式

    1. RDB:每隔一段時間,就會對當前Redis內存中的數據生成一份全量的快照文件
    2. AOF:將對數據的操作記錄寫在aof日誌文件中(此時是將數據寫入操作系統的OS Cache中),然後每隔一段時間(可配置,默認1s)調用操作系統的fsync操作,強制將OS Cache刷到磁盤文件中。Redis只會寫一個AOF文件,這樣會導致AOF文件越來越大,當AOF文件膨脹到一定程度時,AOF會進行rewrite操作,基於當前Redis內存中最新的數據,重新構造一個新的更小的AOF文件,然後刪除舊的大AOF文件。
  2. 持久化相關細節

    1. 由於內存的大小是一定的,當Redis內存中的數據達到上限時,Redis會基於淘汰算法(默認LRU),自動清除一部分數據。
    2. 如果同時開啓了RDB和AOF兩種持久化策略,則Redis重啓時,會默認通過AOF文件重新構建數據庫,因爲AOF文件中的數據更爲完整。
  3. RDB的優缺點

    1. 優點

      1. RDB會生成多個文件,每個文件都代表了當時時刻Redis的全量數據,因此RDB文件十分適合用來做冷備份,可以定時生成備份文件,並保存到安全的雲存儲上。
      2. 由於進行RDB持久化時,主進程只需fork一個子進程,由子進程來執行RDB文件的IO操作,因此對Redis對外提供服務的影響較小,可以讓Redis保存高性能。而AOF每次都需要寫文件,雖然可以快速寫入OS Cache,但是還是需要一定的時間開銷,肯定比RDB略慢一些。
      3. 通過RDB文件恢復數據比AOF文件更快。因爲RDB存放的是數據快照,恢復時直接加載到內存中即可。而AOF存放的是指令日誌, 恢復的時候需要重放和執行指令。

      綜合以上優點,RDB特別適合用來做冷備份

    2. 缺點

      1. 一般來說,RDB持久化的時間間隔要比AOF更長,因此可能丟失更多的數據。這也是RDB最大的缺點,也因此RDB不適應做第一優先恢復方案。
      2. RDB在fork子進程來執行文件生成時,如果文件較大,可能會導致對客戶端的服務暫停幾毫秒,甚至幾秒。
  4. AOF的優缺點

    1. 優點

      1. AOF可以更好的維護數據的完整性。一般情況下,AOF的時間間隔是1s,因此最多丟失1s的數據。
      2. AOF日誌文件以append-only模式寫入,所以沒有任何磁盤尋址的開銷,寫入性能非常高,而且文件不容易破損,即使文件尾部破損,也很容易修復。
      3. AOF日誌文件即使過大的時候,出現後臺重寫操作,也不會影響客戶端的讀寫。因爲在rewrite log的時候,會對其中的指令進行壓縮,創建出一份需要恢復數據的最小日誌出來。在創建新日誌文件的時候,老的日誌文件還是照常寫入。當新的merge後的日誌文件ready的時候,再交換新老日誌文件即可。
      4. AOF日誌文件的命令通過人類可讀的方式進行記錄,這個特性非常適合做災難性的誤刪除的緊急恢復。比如某人不小心用flushall命令清空了所有數據,只要這個時候後臺rewrite還沒有發生,那麼就可以立即拷貝AOF文件,將最後一條flushall命令給刪了,然後再將該AOF文件放回去,就可以通過恢復機制,自動恢復所有數據。
    2. 缺點

      1. 對於同一份數據來說,AOF日誌文件通常比RDB數據快照文件更大。

      2. AOF開啓後,支持的寫QPS會比RDB支持的寫QPS低,因爲AOF一般會配置成每秒fsync一次日誌文件。當然,每秒一次fsync,性能也還是很高的。

        如果要保證一條數據都不丟,也是可以的,將AOF的fsync設置成每寫入一條數據,就fsync一次即可。但是這樣會導致Redis的QPS大降,並不建議。

      3. 以前AOF發生過bug,就是通過AOF記錄的日誌,進行數據恢復的時候,沒有恢復一模一樣的數據出來。所以說,類似AOF這種較爲複雜的基於命令日誌/merge/回放的方式,比基於RDB每次持久化一份完整的數據快照文件的方式,更加脆弱一些,容易有bug。不過AOF爲了避免rewrite過程導致的bug,因此每次rewrite並不是基於舊的指令日誌進行merge的,而是基於當時內存中的數據進行指令的重新構建,這樣健壯性會好很多。

      4. 唯一的比較大的缺點,其實就是做數據恢復的時候,會比較慢。而且做冷備、定期的備份不太方便,可能要自己手寫複雜的腳本去做。

  5. 持久化方案最佳實踐

    建議同時開啓AOF和RDB。

    1. 如果僅僅使用RDB,可能會造成大量數據的丟失。
    2. 如果僅僅使用AOF,則丟失了RDB冷備份的優勢,僅僅通過AOF恢復數據會比較慢。
    3. 綜合使用AOF和RDB兩種持久化機制,用AOF來保證數據不丟失,作爲數據恢復的第一選擇; 用RDB來做不同程度的冷備,在AOF文件都丟失或損壞不可用的時候,還可以使用RDB來進行快速的數據恢復。

三. RDB機制

  1. RDB配置及命令

    RDB機制默認開啓

    #每隔60s,如果有超過1000個key發生了變更,那麼就生成一個新的dump.rdb文件,就是當前redis內存中完整的數據快#照,這個操作也被稱之爲snapshotting
    save 60 1000
    

    快照也可以手動調用save或者bgsave命令,同步或異步執行rdb快照生成。

    save可以設置多個,就是多個snapshotting檢查點。每到一個檢查點,就會去check一下,是否有指定的key數量發生了變更,如果有,就生成一個新的dump.rdb文件

  2. RDB工作流程

    1. Redis根據配置的save時間,生成檢查點。每到一個檢查點,就會去check一下,該時間間隔內是否有超過指定數量的key發生了變化。
    2. 如果有超過指定數量的key發生了變化,則Redis會fork一個子進程。
    3. 子進程嘗試將數據dump到一個臨時的rdb文件中。
    4. rdb快照文件生成後,用新的文件替換舊的dump.rdb。
  3. 一些細節

    1. 每個Redis進程,同一時刻只會存在一個dump.rdb文件。新生成的快照會將舊的覆蓋。
    2. 通過redis-cli shutdown這種方式去停掉redis,其實是一種安全退出的模式,redis在退出的時候會將內存中的數據立即生成一份完整的rdb快照。
    3. 如果Redis意外宕機,且當前時間還未到檢查點,則這段時間內產生的數據並不會持久化到快照文件中,就會丟失數據。可以通過kill -9模擬。

四. AOF機制

  1. AOF配置

    AOF機制默認關閉,需要手動開啓

    #開啓AOF
    appendonly yes
    
    #AOF 的fsync策略
    # appendfsync always
    appendfsync everysec
    # appendfsync no
    
  2. AOF工作流程

    Redis開啓AOF策略後,每接收到一條寫命令,都會將該日誌寫入OS Cache中,然後調用操作系統的fsync()函數將日誌寫入磁盤。Redis提供了三種fsync的時機:

    1. always:每次寫入一條數據,立即將這個數據對應的寫日誌fsync到磁盤上去,性能非常非常差,吞吐量很低。除非要求確保一條數據都不丟失,否則不建議使用這個配置。
    2. everysec:每秒將OS Cache中的數據fsync到磁盤。這是默認配置,一般生產環境下也使用此配置,性能有保障,QPS還是可以上萬的。
    3. no:完全依賴操作系統底層的fsync機制,在Redis層面不可控,可能會造成數據丟失,不建議使用。
  3. AOF rewrite機制

    Redis內存中的數據是不斷變化的,可能會自動化過期,也可能被手動刪除。而且,由於內存大小的限制,Redis當內存佔用量超過一定值時,會通過淘汰策略清除一部分key。這樣一來,可能導致一些已經在內存中不存在的數據仍然保持在AOF日誌文件中,AOF文件可能會膨脹地很大。因此,Redis提供了AOF rewrite的機制,會在後臺對AOF文件進行重寫,以縮小文件的容量。

    Redis 2.4之前,需要手動開發一些腳本,去定時通過BGREWRITEAOF命令去執行AOF rewrite。但是redis 2.4之後,會自動進行rewrite操作。

    用戶可以配置rewrite的觸發條件:

    #當AOF文件增長到上次的百分之多少時,觸發rewrite
    auto-aof-rewrite-percentage 100
    
    #執行rewrite所需的最小文件大小
    auto-aof-rewrite-min-size 64mb
    
  4. rewrite 執行流程

    1. Redis fork子進程
    2. 子進程基於當前Redis內存中的數據,構建日誌,創建一個新的臨時的AOF文件並執行寫入操作。
    3. Redis主進程會繼續接收客戶端的寫請求,將日誌寫入內存,同時也會寫入舊的AOF文件。
    4. 子進程寫完新的AOF文件後,主進程會將這段時間內內存中生成的新日誌追加到新的AOF文件中。
    5. 寫入完成,用新的AOF文件替換舊的。
  5. AOF文件的修復

    如果Redis在向AOF文件append日誌時,突然宕機,可能會導致AOF文件由於不完整而破損。此時,可以通過redis-check-aof --fix命令來修復破損的AOF文件。redis-check-aof命令會刪除不完整的AOF日誌。

五. AOF和RDB同時工作

  1. RDB的snapshotting操作和AOF的rewrite操作不會同時執行。
  2. 如果RDB在執行snapshotting時,用戶執行BGREWRITEAOF命令,那麼等RDB快照生成之後,纔會去執行AOF rewrite。
  3. 如果dump.rdb文件和appendonly.aof文件同時存在,那麼redis重啓的時候,會優先使用AOF進行數據恢復,因爲其中的日誌更完整。

六. 企業級數據備份方案

RDB非常適合做冷備,每次生成之後,就不會再有修改了。

數據備份的主要目的是出現數據錯誤時進行恢復。

  1. 通過crontab定時調度腳本去做數據備份。
  2. 每小時都copy一份rdb的備份,到一個目錄中去,僅僅保留最近48小時的備份。
  3. 每天都保留一份當日的rdb的備份,到一個目錄中去,僅僅保留最近1個月的備份。
  4. 每次copy備份的時候,都把太舊的備份給刪了。
  5. 每天晚上將當前服務器上所有的數據備份,發送一份到遠程的雲服務上去。

七. 企業級數據恢復方案

  1. 如果是redis進程掛掉,那麼重啓redis進程即可,直接基於AOF日誌文件恢復數據。默認的fsync配置,最多丟失1s的數據。
  2. 如果是redis進程所在機器掛掉,那麼重啓機器後,嘗試重啓redis進程,直接基於AOF日誌文件進行數據恢復。如果AOF文件有破損,可以通過redis-check-aof腳本進行修復。
  3. 如果redis當前最新的AOF和RDB文件都出現了丟失/損壞,那麼可以嘗試基於該機器上當前的某個最新的RDB數據副本進行數據恢復。這種情況多爲人爲因素引起,如誤刪數據等。
  4. 如果當前機器上的所有RDB文件全部損壞,那麼從遠程的雲服務上拉取最新的RDB快照回來恢復數據。
  5. 如果是發現有重大的數據錯誤,比如某個小時上線的程序一下子將數據全部污染了,數據全錯了,那麼可以選擇某個更早的時間點,對數據進行恢復

八. 補充

  1. 熱備份 VS 冷備份
    1. 熱備份:實時備份,服務不停止,數據是最新的。
    2. 冷備份:週期性備份(如:定時每天凌晨開始備份,備份時服務暫時停止。備份的數據不是最新的。
  2. 通過RDB文件恢復數據的步驟
    1. 關閉Redis
    2. **修改配置文件,禁用掉AOF功能。這一步非常重要。**如果AOF功能處於開啓狀態,則Redis重啓時優先會通過AOF文件恢復數據,即使AOF文件不存在,也會創建一個空的,這樣一來無法通過備份的RDB文件進行數據恢復。
    3. 將備份的RDB文件拷貝到數據目錄下
    4. 重啓Redis,驗證數據是否已恢復。
    5. **通過Redis客戶端熱修改配置,開啓AOF功能,使得AOF和RDB文件中的數據保持一致這一步也很重要。**如果不通過這種方式開啓AOF,而是通過重啓Redis修改配置文件的方式,則又會出現2中的問題,導致數據丟失。
    6. 修改配置文件,開啓AOF功能,重啓Redis。這樣數據就完全恢復了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章