一塊兒看懂Redis兩種持久化方式的原理

Redis爲持久化提供了兩種方式:redis

  • RDB:在指定的時間間隔能對你的數據進行快照存儲。
  • AOF:記錄每次對服務器寫的操做,當服務器重啓的時候會從新執行這些命令來恢復原始的數據。

本文將經過下面內容的介紹,但願可以讓你們更全面、清晰的認識這兩種持久化方式,同時理解這種保存數據的思路,應用於本身的系統設計中。shell

  • 持久化的配置
  • RDB與AOF持久化的工做原理
  • 如何從持久化中恢復數據
  • 關於性能與實踐建議

持久化的配置

爲了使用持久化的功能,咱們須要先知道該如何開啓持久化的功能。安全

RDB的持久化配置

# 時間策略
save 900 1
save 300 10
save 60 10000

# 文件名稱
dbfilename dump.rdb

# 文件保存路徑
dir /home/work/app/redis/data/

# 若是持久化出錯,主進程是否中止寫入
stop-writes-on-bgsave-error yes

# 是否壓縮
rdbcompression yes

# 導入時是否檢查
rdbchecksum yes

配置其實很是簡單,這裏說一下持久化的時間策略具體是什麼意思。服務器

  • save 900 1 表示900s內若是有1條是寫入命令,就觸發產生一次快照,能夠理解爲就進行一次備份
  • save 300 10 表示300s內有10條寫入,就產生快照

下面的相似,那麼爲何須要配置這麼多條規則呢?由於Redis每一個時段的讀寫請求確定不是均衡的,爲了平衡性能與數據安全,咱們能夠自由定製什麼狀況下觸發備份。因此這裏就是根據自身Redis寫入狀況來進行合理配置。app

stop-writes-on-bgsave-error yes 這個配置也是很是重要的一項配置,這是當備份進程出錯時,主進程就中止接受新的寫入操做,是爲了保護持久化的數據一致性問題。若是本身的業務有完善的監控系統,能夠禁止此項配置, 不然請開啓。運維

關於壓縮的配置 rdbcompression yes ,建議沒有必要開啓,畢竟Redis自己就屬於CPU密集型服務器,再開啓壓縮會帶來更多的CPU消耗,相比硬盤成本,CPU更值錢。性能

固然若是你想要禁用RDB配置,也是很是容易的,只須要在save的最後一行寫上:save ""spa

AOF的配置

# 是否開啓aof
appendonly yes

# 文件名稱
appendfilename "appendonly.aof"

# 同步方式
appendfsync everysec

# aof重寫期間是否同步
no-appendfsync-on-rewrite no

# 重寫觸發配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 加載aof時若是有錯如何處理
aof-load-truncated yes

# 文件重寫策略
aof-rewrite-incremental-fsync yes

仍是重點解釋一些關鍵的配置:debug

appendfsync everysec 它其實有三種模式:設計

  • always:把每一個寫命令都當即同步到aof,很慢,可是很安全
  • everysec:每秒同步一次,是折中方案
  • no:redis不處理交給OS來處理,很是快,可是也最不安全

通常狀況下都採用 everysec 配置,這樣能夠兼顧速度與安全,最多損失1s的數據。

aof-load-truncated yes 若是該配置啓用,在加載時發現aof尾部不正確是,會向客戶端寫入一個log,可是會繼續執行,若是設置爲 no ,發現錯誤就會中止,必須修復後才能從新加載。

工做原理

關於原理部分,咱們主要來看RDB與AOF是如何完成持久化的,他們的過程是如何。

在介紹原理以前先說下Redis內部的定時任務機制,定時任務執行的頻率能夠在配置文件中經過 hz 10 來設置(這個配置表示1s內執行10次,也就是每100ms觸發一次定時任務)。該值最大可以設置爲:500,可是不建議超過:100,由於值越大說明執行頻率越頻繁越高,這會帶來CPU的更多消耗,從而影響主進程讀寫性能。

定時任務使用的是Redis本身實現的 TimeEvent,它會定時去調用一些命令完成定時任務,這些任務可能會阻塞主進程致使Redis性能降低。所以咱們在配置Redis時,必定要總體考慮一些會觸發定時任務的配置,根據實際狀況進行調整。

RDB的原理

在Redis中RDB持久化的觸發分爲兩種:本身手動觸發與Redis定時觸發。

針對RDB方式的持久化,手動觸發可使用:

  • save:會阻塞當前Redis服務器,直到持久化完成,線上應該禁止使用。
  • bgsave:該觸發方式會fork一個子進程,由子進程負責持久化過程,所以阻塞只會發生在fork子進程的時候。

而自動觸發的場景主要是有如下幾點:

  • 根據咱們的 save m n 配置規則自動觸發;
  • 從節點全量複製時,主節點發送rdb文件給從節點完成複製操做,主節點會觸發 bgsave
  • 執行 debug reload 時;
  • 執行 shutdown時,若是沒有開啓aof,也會觸發。

因爲 save 基本不會被使用到,咱們重點看看 bgsave 這個命令是如何完成RDB的持久化的。
image1

這裏注意的是 fork 操做會阻塞,致使Redis讀寫性能降低。咱們能夠控制單個Redis實例的最大內存,來儘量下降Redis在fork時的事件消耗。以及上面提到的自動觸發的頻率減小fork次數,或者使用手動觸發,根據本身的機制來完成持久化。

AOF的原理

AOF的整個流程大致來看能夠分爲兩步,一步是命令的實時寫入(若是是 appendfsync everysec 配置,會有1s損耗),第二步是對aof文件的重寫。

對於增量追加到文件這一步主要的流程是:命令寫入=》追加到aof_buf =》同步到aof磁盤。那麼這裏爲何要先寫入buf在同步到磁盤呢?若是實時寫入磁盤會帶來很是高的磁盤IO,影響總體性能。

aof重寫是爲了減小aof文件的大小,能夠手動或者自動觸發,關於自動觸發的規則請看上面配置部分。fork的操做也是發生在重寫這一步,也是這裏會對主進程產生阻塞。

手動觸發: bgrewriteaof自動觸發 就是根據配置規則來觸發,固然自動觸發的總體時間還跟Redis的定時任務頻率有關係。

下面來看看重寫的一個流程圖:
image2

對於上圖有四個關鍵點補充一下:

  1. 在重寫期間,因爲主進程依然在響應命令,爲了保證最終備份的完整性;所以它依然會寫入舊的AOF file中,若是重寫失敗,可以保證數據不丟失。
  2. 爲了把重寫期間響應的寫入信息也寫入到新的文件中,所以也會爲子進程保留一個buf,防止新寫的file丟失數據。
  3. 重寫是直接把當前內存的數據生成對應命令,並不須要讀取老的AOF文件進行分析、命令合併。
  4. AOF文件直接採用的文本協議,主要是兼容性好、追加方便、可讀性高可認爲修改修復。
不能是RDB仍是AOF都是先寫入一個臨時文件,而後經過 rename 完成文件的替換工做。

從持久化中恢復數據

數據的備份、持久化作完了,咱們如何從這些持久化文件中恢復數據呢?若是一臺服務器上有既有RDB文件,又有AOF文件,該加載誰呢?

其實想要從這些文件中恢復數據,只須要從新啓動Redis便可。咱們仍是經過圖來了解這個流程:
image2

啓動時會先檢查AOF文件是否存在,若是不存在就嘗試加載RDB。那麼爲何會優先加載AOF呢?由於AOF保存的數據更完整,經過上面的分析咱們知道AOF基本上最多損失1s的數據。

性能與實踐

經過上面的分析,咱們都知道RDB的快照、AOF的重寫都須要fork,這是一個重量級操做,會對Redis形成阻塞。所以爲了避免影響Redis主進程響應,咱們須要儘量下降阻塞。

  1. 下降fork的頻率,好比能夠手動來觸發RDB生成快照、與AOF重寫;
  2. 控制Redis最大使用內存,防止fork耗時過長;
  3. 使用更牛逼的硬件;
  4. 合理配置Linux的內存分配策略,避免由於物理內存不足致使fork失敗。

在線上咱們到底該怎麼作?我提供一些本身的實踐經驗。

  1. 若是Redis中的數據並非特別敏感或者能夠經過其它方式重寫生成數據,能夠關閉持久化,若是丟失數據能夠經過其它途徑補回;
  2. 本身制定策略按期檢查Redis的狀況,而後能夠手動觸發備份、重寫數據;
  3. 單機若是部署多個實例,要防止多個機器同時運行持久化、重寫操做,防止出現內存、CPU、IO資源競爭,讓持久化變爲串行;
  4. 能夠加入主從機器,利用一臺從機器進行備份處理,其它機器正常響應客戶端的命令;
  5. RDB持久化與AOF持久化能夠同時存在,配合使用。

本文的內容主要是運維上的一些注意點,但咱們開發者瞭解到這些知識,在某些時候有助於咱們發現詭異的bug。接下來會介紹Redis的主從複製與集羣的知識。

相關文章
相關標籤/搜索