天天看點

Redis持久化

1、簡介

Redis的非常快,很大一部分原因是因為Redis的資料存儲在記憶體中,既然在記憶體中,那麼當伺服器當機或者斷電的時候,資料就會全部丢失了,是以Redis提供了兩種機制來保證Redis資料不會因為故障而全部丢失,這種機制稱為Redis的持久化機制。

Redis的持久化機制有兩種:

  • RDB(Redis Data Base) 記憶體快照
  • AOF(Append Only File) 增量日志

RDB(Redis DataBase) 指的是在指定的時間間隔内将記憶體中的資料集快照寫入磁盤,RDB是記憶體快照(記憶體資料的二進制序列化形式)的方式持久化,每次都是從Redis中生成一個快照進行資料的全量備份。

優點:

  • 存儲緊湊,節省記憶體空間
  • 恢複速度非常快
  • 适合全量備份、全量複制的場景,經常用于災難恢複(對資料的完整性和一緻性要求相對較低的場合)

缺點:

  • 容易丢失資料,容易丢失兩次快照之間Redis伺服器中變化的資料。
  • RDB通過fork子程序對記憶體快照進行全量備份,是一個重量級操作,頻繁執行成本高。
  • fork子程序,雖然共享記憶體,但是如果備份時記憶體被修改,最大可能膨脹到2倍大小。

AOF(Append Only File)是把所有對記憶體進行修改的指令(寫操作)以獨立日志檔案的方式進行記錄,重新開機時通過執行AOF檔案中的Redis指令來恢複資料。AOF能夠解決資料持久化實時性問題,是現在Redis持久化機制中主流的持久化方案(後續會談到4.0以後的混合持久化)。

  • 資料的備份更加完整,丢失資料的機率更低,适合對資料完整性要求高的場景
  • 日志檔案可讀,AOF可操作性更強,可通過記錄檔檔案進行修複
  • AOF日志記錄在長期運作中逐漸龐大,恢複起來非常耗時,需要定期對AOF日志進行瘦身處理(後續詳述)
  • 恢複備份速度比較慢
  • 同步寫操作頻繁會帶來性能壓力

官網位址

http://www.redis.io

2、RDB

2.1 簡介

RDB持久化方案進行備份時,Redis會單獨fork一個子程序來進行持久化,會将資料寫入一個臨時檔案中,持久化完成後替換舊的RDB檔案。在整個持久化過程中,主程序(為用戶端提供服務的程序)不參與IO操作,這樣能確定Redis服務的高性能,RDB持久化機制适合對資料完整性要求不高但追求高效恢複的使用場景。

下面展示RDB持久化流程:

Redis持久化

2.2 Fork

上面說到了RDB持久化過程中,主程序會fork一個子程序來負責RDB的備份,這裡簡單介紹一下fork

  • Linux作業系統中的程式,fork會産生一個和父程序完全相同的子程序。子程序與父程序所有的資料均一緻,但是子程序是一個全新的程序,與原程序是父子程序關系
  • 出于效率考慮,Linux作業系統中使用COW(Copy On Write)寫時複制機制,fork子程序一般情況下與父程序共同使用一段實體記憶體,隻有在程序空間中的記憶體發生修改時,記憶體空間才會複制一份出來。

在Redis中,RDB持久化就是充分的利用了這項技術,Redis在持久化時調用glibc函數fork一個子程序,全權負責持久化工作,這樣父程序仍然能繼續給用戶端提供服務。fork的子程序初始時與父程序(Redis的主程序)共享同一塊記憶體;當持久化過程中,用戶端的請求對記憶體中的資料進行修改,此時就會通過COW機制對資料段頁面進行分離,也就是複制一塊記憶體出來給主程序去修改。

Redis持久化

RDB觸發的規則分為兩大類,分别是手動觸發和自動觸發:

自動觸發:

  1. 配置觸發規則
  2. shutdown觸發
  3. flushall觸發

手動觸發:

  1. save
  2. bgsave

2.3 自動觸發

以下介紹Redis的RDB持久化機制中的自動觸發機制中的配置觸發規則來觸發RDB,涉及到RDB規則的配置、檔案存儲路徑配置、檔案名配置、檔案壓縮配置、檔案完整性校驗配置。

2.3.1 配置規則觸發

  • 在Redis安裝目錄下的redis.conf配置檔案中搜尋 /snapshot即可快速定位,配置檔案預設注釋了下面三行資料,通過配置規則來觸發RDB的持久化,需要開啟或者根據自己的需求按照規則來配置。
Redis持久化

下面對配置規則進行解釋,實際使用過程中可以根據需求進行合理的配置

save 3600 1 -> 3600秒内有1個key被修改,觸發RDB

save 300 100 -> 300 秒内有100個key被修改,觸發RDB

save 60 10000 -> 60 秒内有10000個key被修改,觸發RDB

  • 配置RDB檔案的存儲路徑
Redis持久化

我們可以在Redis的安裝目錄下看到dump.rdb檔案,如果沒看到,連接配接到用戶端執行一次shutdown,這個是後面

shutdown自動觸發規則,後續會講述

Redis持久化
  • 配置RDB檔案的名稱
Redis持久化
  • 配置RDB檔案壓縮

Redis預設會使用LZF算法對Redis的RDB檔案進行壓縮,這會消耗一定的CPU計算資源,但是會帶來空間上的節省

Redis持久化
  • 配置RDB檔案完整性校驗

Redis 預設使用CRC64的算法,對RDB檔案完整性進行校驗,以此來保證RDB檔案的完整

Redis持久化

2.3.2 shutdown觸發

shutdown觸發Redis的RDB持久化機制非常簡單,我們在用戶端執行shutdown即可。

Redis持久化

2.3.3 flushall觸發

首先這裡一定要特别注意,flushall是删庫跑路,它是清空dump.rdb檔案,千萬千萬不要看了部落客的文章,跑到公司備份的時候順手來個flushall,然後到時候來問候我……,這個flushall是為了清空Redis資料的同時清空dump.rdb檔案,要不然重新開機Redis的時候,資料又會恢複到上一次備份的時候的資料,與flushall的執行指令含義就沖突了。

為了證明這個檔案不會保留資料,我特地特地的寫個腳本測試一下:

編寫一個批量插入的腳本檔案

vi batchKeyInsert.sh

#!/bin/bash

for((i=0;i<100000;i++))

do

echo -en "Hello Redis." | redis-cli -h 192.168.211.108 -p 6379 -c -x set name$i >>redis.log

done

檔案賦權

chmod +x batchKeyInsert.sh

Redis持久化

./batchKeyInsert.sh

Redis持久化

此時檢視dump.rdb

Redis持久化

執行flushall,後再次檢視,rbd檔案被清空

Redis持久化

2.2 手動觸發

手動觸發RDB持久化的方式可以使用save指令和bgsave指令,這兩個指令的差別如下。

save:執行save指令,阻塞Redis的其他操作,會導緻Redis無法響應用戶端請求,不建議使用。

bgsave:執行bgsave指令,Redis背景異步進行快照的儲存操作,此時Redis仍然能響應用戶端的請求。

2.3 RDB持久化檔案的備份

在實際的生産環境中,我們一般不會使用主節點Master來進行持久化備份,我們會通過在Redis的多個從伺服器上進行RDB持久化備份,這樣是為了對Redis資料的多次備份,防止出現網絡分區或者部分節點當機甚至是硬體損壞的情況發生。

作為運維或者架構師,李子捌覺得應該要定時定期的通過腳本對Redis持久化檔案進行轉移備份,這樣雙重保險,更加可靠,萬一遇到突發情況,也是多一手解決方案。

3、AOF

3.1 簡介

Redis配置檔案中開啟,AOF持久化方案進行備份時,用戶端所有請求的寫指令都會被追加到AOF緩沖區中,緩沖區中的資料會根據Redis配置檔案中配置的同步政策來同步到磁盤上的AOF檔案中,同時當AOF的檔案達到重寫政策配置的門檻值時,Redis會對AOF日志檔案進行重寫,給AOF日志檔案瘦身。Redis服務重新開機的時候,通過加載AOF日志檔案來恢複資料。

Redis持久化

3.2 AOF配置

3.2.1 基本配置

AOF預設不開啟,預設為appendonly no,開啟則需要修改為appendonly yes

Redis持久化

AOF配置檔案的名稱預設為appendonly.aof

Redis持久化

配置檔案的位址可以通過在redis用戶端執行config get dir擷取,其儲存路徑與RDB一緻

Redis持久化

3.2.2 同步頻率配置

AOF日志是以檔案的形式存在的,當程式對AOF日志檔案進行寫操作時,實際上将内容寫到了核心為檔案描述符配置設定的一個記憶體緩沖區中,随後核心會異步的将緩沖區中的資料重新整理到磁盤中。如果緩沖區中的資料沒來得及刷回磁盤時,伺服器當機了,這些資料就會丢失。

是以Redis通過調用Linux作業系統的glibc提供的fsync(int fid)來将指定檔案的内容強制從核心緩沖區刷回磁盤,以此來保證緩沖區中的資料不會丢失。不過這是一個IO操作,相比Redis的性能來說它是非常慢的,是以不能頻繁的執行。

Redis配置檔案中有三種重新整理緩沖區的配置:

appendfsync always

每次Redis寫操作,都寫入AOF日志,這種配置理論上Linux作業系統扛不住,因為Redis的并發遠遠超過了Linux作業系統提供的最大重新整理頻率,就算Redis寫操作比較少的情況,這種配置也是非常耗性能的,因為涉及到IO操作,是以這個配置基本上不會用

appendfsync everysec

每秒重新整理一次緩沖區中的資料到AOF檔案,這個Redis配置檔案中預設的政策,相容了性能和資料完整性的折中方案,這種配置,理論上丢失的資料在一秒鐘左右

appendfsync no

Redis程序不會主動的去重新整理緩沖區中的資料到AOF檔案中,而是直接交給作業系統去判斷,這種操作也是不推薦的,丢失資料的可能性非常大。

Redis持久化

注意要重新整理緩沖區的資料到磁盤需要将如下配置,配置為no,不是yes

no-appendfsync-on-rewrite no

3.2.3 AOF修複功能

AOF持久化機制正常恢複與RDB持久化機制的恢複是一樣的,都隻需要将備份檔案放置到Redis的工作目錄下,Redis啟動時就會自動的加載。AOF持久化機制提供了AOF檔案異常時恢複的功能,這個功能在AOF檔案損壞的場景中經常被使用到。

測試,清空Redis服務中的資料

Redis持久化

寫入資料

Redis持久化

AOF日志檔案每秒會被重新整理一次資料,此時資料已經寫入了appendonly.aof檔案

Redis持久化

打開檔案我們可以非常清除的閱讀AOF的檔案内容,看到Redis的指令序列

Redis持久化

此時人為的進行資料破壞

Redis持久化

再次啟動發現無法啟動(我配置的别名啟動)

Redis持久化

執行redis-check-aof --fix ../appendonly.aof 對AOF日志檔案進行修複

Redis持久化

修複過程中會有部分資料丢失

Redis持久化

連接配接用戶端檢視資料

Redis持久化

3.2.4 AOF重寫

前面提到AOF的缺點時,說過AOF屬于日志追加的形式來存儲Redis的寫指令,這會導緻大量備援的指令存儲,進而使得AOF日志檔案非常龐大,比如同一個key被寫了10000次,最後卻被删除了,這種情況不僅占記憶體,也會導緻恢複的時候非常緩慢,是以Redis提供重寫機制來解決這個問題。Redis的AOF持久化機制執行重寫後,儲存的隻是恢複資料的最小指令集,我們如果想手動觸發可以使用如下指令:

bgrewriteaof

Redis4.0後的重寫使用的是RDB快照和AOF指令拼接的方式,在AOF檔案的頭部是RDB快照的二進制形式的資料,尾部是快照産生後發生的寫入操作的指令。

由于重寫AOF檔案時,會對Redis的性能帶來一定的影響,是以也不能随便的進行自動重寫,Redis提供兩個配置用于自動進行AOF重寫的名額,隻有這兩個名額同時滿足的時候才會發生重寫:

Redis持久化

auto-aof-rewrite-percentage 100:指的是當檔案的記憶體達到原先記憶體的兩倍

auto-aof-rewrite-min-size 64mb:指的是檔案重寫的最小記憶體大小

AOF重寫流程如下:

  1. bgrewriteaof觸發重寫,判斷是否存在bgsave或者bgrewriteaof正在執行,存在則等待其執行結束再執行
  2. 主程序fork子程序,防止主程序阻塞無法提供服務,類似RDB
  3. 子程序周遊Redis記憶體快照中資料寫入臨時AOF檔案,同時會将新的寫指令寫入aof_buf和aof_rewrite_buf兩個重寫緩沖區,前者是為了寫會舊的AOF檔案,後者是為了後續重新整理到臨時AOF檔案中,防止快照記憶體周遊時新的寫入操作丢失
  4. 子程序結束臨時AOF檔案寫入後,通知主程序
  5. 主程序會将上面3中的aof_rewirte_buf緩沖區中的資料寫入到子程序生成的臨時AOF檔案中
  6. 主程序使用臨時AOF檔案替換舊AOF檔案,完成整個重寫過程
Redis持久化

4、混合持久化

Redis4.0後大部分的使用場景都不會單獨使用RDB或者AOF來做持久化機制,而是兼顧二者的優勢混合使用。其原因是RDB雖然快,但是會丢失比較多的資料,不能保證資料完整性;AOF雖然能盡可能保證資料完整性,但是性能确實是一個诟病,比如重放恢複資料。

其日志檔案結構如下:

Redis持久化

混合持久化通過aof-use-rdb-preamble yes開啟,Redis 4.0以上版本預設開啟

Redis持久化

測試,我們先插入一些key,然後執行BGREWRITEAOF觸發AOF持久化後,再插入一些key

Redis持久化

此時将會看到如下的效果,驗證了混合持久化的方式

Redis持久化

5、總結

最後來總結這兩者,到底用哪個更好呢?

  • 推薦是兩者均開啟
  • 如果對資料不敏感,可以選單獨用RDB
  • 不建議單獨用AOF,因為可能會出現Bug
  • 如果隻是做純記憶體緩存,可以都不用

Redis官網是這麼介紹的:

Redis持久化

看不懂就看下Redis中文網的介紹:

Redis持久化

Redis官網關于持久化的介紹

https://redis.io/topics/persistence

Redis中文網關于持久化的介紹

http://redis.cn/topics/persistence.html