前言
- 文章首發於微信公眾號【碼猿技術專欄】:天天用Redis,持久化方案有哪些你知道嗎?
- Redis目前已經成為主流的記憶體資料庫了,但是大部分人僅僅是停留在會用的階段,你真的瞭解Redis內部的工作原理嗎?
- 今天這篇文章將為大家介紹Redis持久化的兩種方案,文章將會從以下五個方面介紹:
- 什麼是RDB,RDB如何實現持久化?
- 什麼是AOF,AOF如何實現持久化?
- AOF和RDB的區別。
- 如何重啟恢復資料?
- 持久化效能問題和解決方案
RDB
- RDB持久化是把當前程式資料生成快照儲存到硬碟的過程, 觸發RDB持久化過程分為手動觸發和自動觸發。
- RDB完成後會自動生成一個檔案,儲存在
dir
配置的指定目錄下,檔名是dbfileName
指定。
- Redis預設會採用LZF演算法對生成的RDB檔案做壓縮處理,壓縮後的檔案遠遠小於記憶體大小,預設開啟。
手動觸發
- 手動觸發的命令有
save
和bgsave
。
save
:該命令會阻塞Redis伺服器,直到RDB的過程完成,已經被廢棄,因此線上不建議使用。
bgsave
:每次進行RDB過程都會fork一個子程式,由子程式完成RDB的操作,因此阻塞只會發生在fork階段,一般時間很短。
自動觸發
- 除了手動觸發RDB,Redis伺服器內部還有如下幾個場景能夠自動觸發RDB:
- 根據我們的
save m n
配置規則自動觸發。
- 如果從節點執行全量複製操作, 主節點自動執行bgsave生成RDB檔案併傳送給從節點。
- 執行
debug reload
命令重新載入Redis時, 也會自動觸發save操作。
- 預設情況下執行shutdown命令時, 如果沒有開啟AOF持久化功能則自動執行
bgsave
。
RDB執行流程
- RDB的主流方式就是bgsave,通過下圖我們來看看RDB的執行流程:
- 通過上圖可以很清楚RDB的執行流程,如下:
- 執行bgsave命令後,會先判斷是否存在AOF或者RDB的子程式,如果存在,直接返回。
- 父程式fork操作建立一個子程式,fork操作中父程式會被阻塞。
- fork完成後,子程式開始根據父程式的記憶體生成臨時快照檔案,完成後對原有的RDB檔案進行替換。執行
lastsave
命令可以檢視最近一次的RDB時間。
- 子程式完成後傳送訊號給父程式,父程式更新統計資訊。
RDB的優點
- RDB是一個緊湊壓縮的二進位制檔案, 代表Redis在某個時間點上的資料快照。 非常適用於備份, 全量複製等場景。 比如每6小時執行
bgsave
備份,並把RDB檔案拷貝到遠端機器或者檔案系統中,用於災難恢復。
- Redis載入
RDB
恢復資料遠遠快於AOF
的方式。
RDB的缺點
- RDB方式資料沒辦法做到
實時持久化
/秒級持久化
。 因為bgsave每次執行都要執行fork操作建立子程式,屬於重量級操作,頻繁執行成本過高。
- RDB檔案使用特定二進位制格式儲存, Redis版本演進過程中有多個格式的RDB版本, 存在老版本Redis服務無法相容新版RDB格式的問題。
AOF
AOF
(append only file) 持久化: 以獨立日誌的方式記錄每次寫命令,重啟時再重新執行AOF檔案中的命令達到恢復資料的目的。 AOF的主要作用是解決了資料持久化的實時性, 目前已經是Redis持久化的主流方式
。
如何開啟AOF
- 開啟AOF功能需要設定配置:
appendonly yes
, 預設不開啟。 AOF檔名通過appendfilename
配置設定, 預設檔名是appendonly.aof
。 儲存路徑同RDB持久化方式一致,通過dir
配置指定。
AOF整體的執行流程
- AOF執行的流程大致分為
命令寫入
、檔案同步
、檔案重寫
、重啟載入
四個步驟,如下圖:
- 從上圖大致瞭解了AOF的執行流程,下面一一分析上述的四個步驟。
命令寫入
- AOF命令寫入的內容直接是文字協議格式。 例如
set hello world
這條命 令, 在AOF緩衝區會追加如下文字:
*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n
- 命令寫入是直接寫入到AOF的緩衝區中,至於為什麼?原因很簡單,Redis使用單執行緒響應命令,如果每次寫AOF檔案命令都直接追加到硬碟, 那麼效能完全取決於當前硬碟負載。先寫入緩衝區
aof_buf
中, 還有另一個好處, Redis可以提供多種緩衝區 同步硬碟的策略,在效能和安全性方面做出平衡。
檔案同步
- Redis提供了多種AOF緩衝區同步檔案策略, 由引數
appendfsync
控制,如下:
- 配置為
always
時, 每次寫入都要同步AOF檔案, 在一般的SATA硬碟上,Redis只能支援大約幾百TPS寫入, 顯然跟Redis高效能特性背道而馳,不建議配置。
- 配置為
no
,由於作業系統每次同步AOF檔案的週期不可控,而且會加大每次同步硬碟的資料量,雖然提升了效能,但資料安全性無法保證。
- 配置為
everysec
(預設的配置),是建議的同步策略, 也是預設配置,做到兼顧效能和資料安全性。理論上只有在系統突然當機的情況下丟失1秒的資料(當然,這是不太準確的)。
檔案重寫機制
- 隨著命令不斷寫入AOF, 檔案會越來越大, 為了解決這個問題, Redis引入AOF重寫機制壓縮檔案體積。 AOF檔案重寫是把Redis程式內的資料轉化為寫命令同步到新AOF檔案的過程。
- 為什麼要檔案重寫呢? 因為檔案重寫能夠使得AOF檔案的體積變得更小,從而使得可以更快的被Redis載入。
- 重寫過程分為手動觸發和自動觸發。
- 手動觸發直接使用
bgrewriteaof
命令。
- 根據
auto-aof-rewrite-min-size
和auto-aof-rewrite-percentage
引數確定自動觸發時機。
auto-aof-rewrite-min-size
:表示執行AOF重寫時檔案最小體積, 預設為64MB。
auto-aof-rewrite-percentage
:代表當前AOF檔案空間(aof_current_size
) 和上一次重寫後AOF檔案空間(aof_base_size
) 的比值。
- 自動觸發時機相當於aof_current_size>auto-aof-rewrite-minsize&&(aof_current_size-aof_base_size) /aof_base_size>=auto-aof-rewritepercentage。其中
aof_current_size
和aof_base_size
可以在info Persistence
統計資訊中檢視。
- 那麼檔案重寫後的AOF檔案為什麼會變小呢? 有如下幾個原因:
- 程式內已經超時的資料將不會再次寫入AOF檔案中。
- 舊的AOF檔案含有無效命令,如
del key1
、 hdel key2
等。重寫使用程式內資料直接生成,這樣新的AOF檔案只保留最終資料的寫入命令。
- 多條寫命令可以合併為一個, 如:
lpush list a
、 lpush list b
、lpush listc
可以轉化為:lpush list a b c
。為了防止單條命令過大造成客戶端緩衝區溢位,對於list
、 set
、 hash
、 zset
等型別操作,以64個元素為界拆分為多條。
- 介紹了檔案重寫的系列知識,下面來看看Redis內部是如何進行檔案重寫的,如下圖:
- 看完上圖,大致瞭解了檔案重寫的流程,對於重寫的流程,補充如下:
- 重寫期間,主執行緒並沒有阻塞,而是在執行其他的操作命令,依然會向舊的AOF檔案寫入資料,這樣能夠保證備份的最終完整性,如果資料重寫失敗,也能保證資料不會丟失。
- 為了把重寫期間響應的寫入資訊也寫入到新的檔案中,因此也會為子程式保留一個緩衝區,防止新寫的檔案丟失資料。
- 重寫是直接把當前記憶體的資料生成對應命令,並不需要讀取老的AOF檔案進行分析、命令合併。
- AOF檔案直接採用的
文字協議
,主要是相容性好、追加方便、可讀性高可認為修改修復。
- 無論是
RDB
還是AOF
都是先寫入一個臨時檔案,然後通過重新命名
完成檔案的替換。
AOF的優點
- 使用 AOF 持久化會讓 Redis 變得非常耐久:你可以設定不同的 fsync 策略,比如無 fsync ,每秒鐘一次 fsync ,或者每次執行寫入命令時 fsync 。 AOF 的預設策略為每秒鐘 fsync 一次,在這種配置下,Redis 仍然可以保持良好的效能,並且就算髮生故障停機,也最多隻會丟失一秒鐘的資料( fsync 會在後臺執行緒執行,所以主執行緒可以繼續努力地處理命令請求)。
AOF的缺點
- 對於相同的資料集來說,AOF 檔案的體積通常要大於 RDB 檔案的體積。根據所使用的 fsync 策略,AOF 的速度可能會慢於 RDB。 在一般情況下, 每秒 fsync 的效能依然非常高, 而關閉 fsync 可以讓 AOF 的速度和 RDB 一樣快, 即使在高負荷之下也是如此。不過在處理巨大的寫入載入時,RDB 可以提供更有保證的最大延遲時間。
- 資料恢復速度相對於RDB比較慢。
AOF和RDB的區別
- RDB持久化是指在指定的時間間隔內將記憶體中的資料集快照寫入磁碟,實際操作過程是fork一個子程式,先將資料集寫入臨時檔案,寫入成功後,再替換之前的檔案,用二進位制壓縮儲存。
- AOF持久化以日誌的形式記錄伺服器所處理的每一個寫、刪除操作,查詢操作不會記錄,以文字的方式記錄,可以開啟檔案看到詳細的操作記錄。
重啟載入
- 無論是RDB還是AOF都可用於伺服器重啟時的資料恢復,執行流程如下圖:
- 上圖很清晰的分析了Redis啟動恢復資料的流程,先檢查AOF檔案是否開啟,檔案是否存在,再檢查RDB是否開啟,檔案是否存在。
效能問題與解決方案
- 通過上面的分析,我們都知道RDB的快照、AOF的重寫都需要fork,這是一個重量級操作,會對Redis造成阻塞。因此為了不影響Redis主程式響應,我們需要儘可能降低阻塞。
- 那麼如何減少fork操作的阻塞呢?
- 優先使用物理機或者高效支援fork操作的虛擬化技術。
- 控制Redis例項最大可用記憶體, fork耗時跟記憶體量成正比, 線上建議每個Redis例項記憶體控制在10GB以內。
- 合理配置Linux記憶體分配策略,避免實體記憶體不足導致fork失敗。
- 降低fork操作的頻率,如適度放寬AOF自動觸發時機,避免不必要的全量複製等。
總結
- 本文介紹了Redis持久化的兩種不同的策略,大部分內容是運維人員需要掌握的,當然作為後端人員也是需要了解一下,畢竟小公司都是一人搞全棧,哈哈。
- 如果覺得陳某寫的不錯,有所收穫的話,關注分享一波,你的關注將是陳某寫作的最大動力,謝謝支援!!!