前言
- 文章首發于微信公眾號【碼猿技術專欄】:天天用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持久化的兩種不同的策略,大部分內容是運維人員需要掌握的,當然作為后端人員也是需要了解一下,畢竟小公司都是一人搞全堆疊,哈哈,
- 如果覺得陳某寫的不錯,有所識訓的話,關注分享一波,你的關注將是陳某寫作的最大動力,謝謝支持!!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/6060.html
標籤:NoSQL
