初識Redis(三):Redis數據備份、恢復與持久化

我們都知道,Redis的讀寫性能俱佳,但由于是內存數據庫,如果沒有提前備份,Redis數據是掉電即失的。好在Redis提供了兩種方式進行持久化:1、RDB持久化 2、AOF持久化

原理

  • RDB持久化:將Redis在內存中的數據定時dump到磁盤上,實際操作過程是fork一個子進程,先將數據寫入臨時文件,寫入成功后,再替換之前的文件,用二進制壓縮存儲
RDB持久化
  • AOF持久化:將Redis的操作日志以文件追加的方式寫入文件,只記錄寫、刪除操作,查詢操作不會記錄(類似于MySQL的Binlog日志)
AOF持久化

RDB持久化實現

Redis數據庫
Redis是一個字典結構的存儲服務器,一個Redis實例提供了多個用來存儲數據的容器, 客戶端可以指定將數據存儲在哪個容器中(類似于MySQL中的數據庫)。
Redis默認支持16個數據庫,可以通redis.conf配置文件修改數據庫個數,客戶端與Redis建立連接之后默認選擇0號數據庫
備份
  • 自動開啟RDB持久化
修改配置文件
after 900 sec (15 min) if at least 1 key changed
900秒(15分鐘)內至少1個key值改變(則進行數據庫保存--持久化)
    
after 300 sec (5 min) if at least 10 keys changed
300秒(5分鐘)內至少10個key值改變(則進行數據庫保存--持久化)
    
after 60 sec if at least 10000 keys changed
60秒(1分鐘)內至少10000個key值改變(則進行數據庫保存--持久化) 

save 900 1
save 300 10
save 60 10000

備份文件的名稱
dbfilename dump.rdb

備份文件存放路徑
dir ./bak   
  • 手動開啟RDB持久化
Redis的SAVE命令和BGSAVE命令用于將當前數據庫備份
127.0.0.1:6379> save
OK

127.0.0.1:6379> bgsave
Background saving started

SAVEBGSAVE命令的區別在于:SAVE命令是阻塞主進程,save操作完成之后,主進程才開始工作,客戶端可以連接;BGSAVE命令是fork一個專門save的子進程,此操作不會影響主進程

注:SAVE只是將當前的數據庫備份,備份文件名默認為dump.rdb,可通過配置文件修改備份文件名 dbfilename xxx.rdb(發現一個問題:如果要對多個數據庫進行備份,那么最終只能備份最后一個數據庫,因為dump.rdb文件會相互覆蓋)

恢復

將備份的RDB文件,放在指定目錄,重啟Redis即可恢復數據
  • 備份的RDB文件: 通過命令redis 127.0.0.1:6379> CONFIG GET dir查看執行SAVE命令之后,redis默認存放備份文件的目錄;通過命令redis 127.0.0.1:6379> CONFIG GET dbfilename查看備份RDB文件的文件名稱;
  • 指定目錄: 通過命令redis 127.0.0.1:6379> CONFIG GET dir,得出redis從哪個目錄讀取備份文件(一般只要直接重啟Redis就能恢復數據,因為備份的默認目錄和啟動讀取的目錄是同一個,但是如果公司有特定的要求,備份文件統一放在其他目錄,此時則需要將待還原的RDB文件mv到這個指定目錄)
PS:在練習恢復數據時,碰到一個坑:

1.set一些數據

2. 執行save命令

3. del所有的key

4. 重啟,發現數據沒有恢復過來

原因:還記得上文提到過的Redis自動RDB備份嗎?我在執行第三步操作時,改變了1個以上的key的值,并且這個時間正好是Redis自動備份900秒的最后一秒,所以此時Redis又自動備份了一次,dump.rdb覆蓋了舊的rdb文件,還原回去,自然是del之后的數據了。(當然我這個不是憑空臆想的哈,是因為我在步驟2執行save時,看了一下dump.rdb文件的大小,98K,在準備重啟之前,我又看了一下dump.rdb文件,73K,說明rdb文件肯定產生了覆蓋)

AOF持久化實現

備份
備份過程分以下三個階段:
  • 命令傳播: Redis將執行完的命令、命令參數等信息發送到AOF程序
  • 緩存追加: AOF程序將接收到的命令內容追加到服務器的AOF緩存中
  • 文件寫入和保存: AOF緩存中的內容被寫入到AOF文件末尾,如果滿足AOF保存條件,寫入的內容會真正保存到磁盤中
進行AOF備份
  • 開啟AOF功能

修改配置文件

#此選項為aof功能的開關,默認為“no”,通過“yes”來開啟aof功能
appendonly yes  

#指定aof文件名稱
appendfilename appendonly.aof

#備份文件存放路徑(此參數同樣適用于指定RDB備份文件存放路徑)
dir ./
  • 設置保存模式

AOF有3種方式將操作命令存入AOF文件

1. appendfsync no 不保存

只執行WHRITE操作,SAVE操作會被略過,只有在Redis被關閉AOF功能被關閉系統的寫緩存被刷新(如緩存已被寫滿)這三種情況,SAVE操作會被執行,但是這三種情況都會引起Redis主進程阻塞

2. appendfsync everysec 每秒鐘保存一次

這種模式中,SAVE原則上每隔一秒鐘就會執行一次,具體的執行周期和文件寫入、保存時,Redis所處的狀態有關,此模式下SAVE操作由后臺子線程調用,不會引起服務器主進程的阻塞

3. appendfsync always 每執行一個命令保存一次
在這種模式下,每執行一個命令,WRITESAVE都會被執行,且SAVE操作會阻塞主進程

模式 WRITE阻塞 SAVE阻塞 停機時丟失的數據量
appendfsync no 阻塞 阻塞 操作系統最后一次對 AOF 文件觸發 SAVE 操作之后的數據
appendfsync everysec 阻塞 不阻塞 一般情況下不超過 2 秒鐘的數據
appendfsync always 阻塞 阻塞 最多只丟失一個命令的數據

設置好AOF寫入的模式之后,只要達到寫入條件(比如一秒鐘、執行一個命令),就會自動在指定路徑下生成AOF文件,并往里面記錄操作命令

AOF文件重寫

AOF文件通過同步Redis服務器所執行的命令,實現對數據庫狀態的記錄。有些被頻繁操作的鍵,對它們所調用的命令可能有成百上千、甚至上萬條,這樣很容易出現AOF文件體積急速膨脹,對Redis甚至整個系統造成影響。

  • AOF重寫實現原理

如果服務器對鍵list執行以下四條命令:

RPUSH list 1 2 3 4      // [1, 2, 3, 4]

RPOP list               // [1, 2, 3]

LPOP list               // [2, 3]

LPUSH list 1            // [1, 2, 3]

那么當前列表鍵list在數據庫的值就是[1,2,3],如果我們要保存這個列表的當前狀態,并且盡可能地減少使用命令數,最簡單的方法是直接讀取list鍵在數據庫的當前值,然后用一條RPUSH list 1 2 3命令代替前面四條命令。

根據鍵的類型,使用適當的寫入命令來重現鍵的當前值,這就是AOF重寫的實現原理

  • AOF后臺重寫

子程序處理: AOF重寫程序,會阻塞主進程,作為一種輔助性的維護手段,Redis不希望AOF重寫造成服務器無法處理請求,所以Redis會將重寫程序放到子進程執行。

AOF重寫緩存: 不過,使用子進程也有一個問題需要解決:子進程在進行AOF重寫期間,主進程還在繼續處理命令,新的數據更新不能同步到重寫后的AOF文件中。為了解決這個問題,Redis增加了一個AOF重寫緩存,這個緩存在fork出子進程之后開始啟用,重寫期間的寫操作,除了會將寫命令追加到現有的AOF文件之外,還會追加到這個緩存中。子進程完成重寫操作之后,它會向父進程發送一個完成信號,父進程接到完成信號之后,會調用一個信號函數,將AOF重寫緩存中的內容寫入新的AOF文件中。

性能影響: 在整個AOF后臺重寫的過程中,只有最后的寫入緩存會造成主進程的阻塞,其他時候,AOF后臺重寫都不會阻塞主進程。

  • 進行后臺重寫:

1. 系統自動后臺重寫(需滿足一定觸發條件):

i 沒有正在執行的BGSAVEBGREWRITEAOF命令

ii 當前AOF文件大小大于aof_rewrite_min_size

iii AOF文件大小和最后一次重寫大小的比率大于aof_rewrite_perc

2. 手動后臺重寫:

通過BGREWRITEAOF手動重寫

恢復

和RDB恢復是一樣的操作,將備份的AOF文件,放在指定目錄,重啟Redis即可恢復數據(具體可參照上文的RDB恢復數據)
ps: 當指定目錄同時有RDB文件和AOF文件時,還原數據時AOF文件的優先級是高于RDB文件的,所以優先通過AOF文件還原數據

二者優缺點

RDB持久化
優點:
  • RDB方式備份,整個Redis數據庫最終備份成一個文件,這對于文件備份而言是完美的(方便管理、還原、壓縮、轉儲)
  • 對服務進程影響最小,唯一需要做的是fork出子進程,之后所有的持久化工作交由子進程處理
  • 相比于AOF機制,如果數據量比較大,RDB的啟動效率會更高(記錄的是源數據,而非數據操作)
缺點:
  • 數據的可用性得不到太大的保障,如果在定時持久化之前出現宕機現象,此前沒來得及寫入磁盤的數據都將丟失
  • 如果數據量較大,fork子進程的操作可能會使服務短暫停止(通常是幾百毫秒)
AOF持久化
優點:
  • 擁有更高的數據可用性,數據持久化最完整
  • 日志文件采用append模式,即使在寫入過程中出現宕機現象,也不會破壞日志文件之前已經存在的內容
  • 提供rewrite機制,當日志過大時,Redis以append模式不斷將修改的日志寫入老的磁盤文件,同時Redis還會創建一個新的文件用于記錄此期間有哪些命令被執行
缺點:
  • 對于相同數量的數據,AOF文件通常大于RDB文件,RDB文件在恢復大數據集的速度比AOF恢復的更快(RDB省去了執行的步驟,直接導入源數據)
總結
RDB持久化,性能更好(所有操作均由子進程處理,主進程不進行任何IO操作),數據一致性一般。AOF持久化,數據一致性更好,性能一般(記錄操作日志,寫入日志和執行日志恢復數據的時間都比RDB更長)。

如果這篇文章對你有幫助,請點個贊哈,感謝

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容