本文主要講了 Redis 的持久化相關功能,持久化一直是影響 Redis 性能的高發地,也是面試中常常被問到的。ios
包括 RDB 相關的特定和優缺點,AOF 的優缺點,事實上,因爲 RDB 的數據實時性問題,目前用 AOF 比較多了,而持久化恢復也是優先 AOF。面試
RDB 是舊的模式,如今基本上都使用 AOF,固然,今天兩個都會一塊兒聊聊。redis
2、RDB
RDB 流程圖:算法
RDB 特色:緩存
- RDB 是一種快照模式,即——保存的是 key value 數據內容。
- RDB 有 2 種持久方式,同步 save 模式和異步 bgsave 模式。因爲 save 是同步的,因此能夠保證數據一致性,而 bgsave 則不能。
- save 能夠在客戶端顯式觸發,也能夠在 shutdown 時自動觸發;bgsave 能夠在客戶端顯式觸發,也能夠經過配置由定時任務觸發,也能夠在 slave 節點觸發。
- save 致使 redis 同步阻塞,基本已經廢棄。bgsave 則不會致使阻塞,但也有缺點:在 fork 時,須要增長內存服務器開銷,由於當內存不夠時,將使用虛擬內存,致使阻塞 Redis 運行。因此,須要保證空閒內存足夠。
- 默認執行 shutdown 時,若是沒有開啓 AOF,則自動執行 bgsave。
- 每次的 RDB 文件都是替換的。
關於優化:安全
Redis 會壓縮 RDB 文件,使用 LZF 算法,讓最終的 RDB 文件遠小於內存大小,默認開啓。但會消耗 CPU。性能優化
RDB 缺點:服務器
- 沒法秒級持久化。
- 老版本 Redis 沒法兼容新版本 RDB。
RDB 優勢:架構
- 文件緊湊,適合備份,全量複製場景。例如每 6 小時執行 bgsave,保存到文件系統之類的。
- Redis 加載 RDB 恢復數據遠遠快於 AOF。
3、AOF
因爲 RDB 的數據實時性問題,AOF(append only file) 是目前 Redis 持久化的主流方式。併發
AOF 特色:
- 默認文件名是 appendonly.aof。和 RDB 同樣,保存在配置中 dir 目錄下。
- AOF 相比較於 RDB,每次都會保存寫命令,數據實時性更高。
- AOF 因爲每次都會記錄寫命令,文件會很大,所以須要進行優化,稱之爲「重寫機制」(下面詳細說)。
- AOF 每次保存的寫命令都放在一個緩衝區,根據不一樣的策略(下面詳細說)同步到磁盤。
「重寫機制」 細節:
- fork 子進程(相似 bgsave)
- 主進程會寫到2個緩衝區,一個是原有的 「AOF 緩存區」,一個是專門爲子進程準備的 「AOF 重寫緩衝區」;
- 子進程寫到到新的 AOF 文件中,批量的,默認 32m;寫完後通知主進程。
- 主進程把「AOF 重寫緩衝區」的數據寫到新 AOF 文件中。
- 將新的 AOF 文件替換老文件。
重寫流程圖:
緩衝區同步策略,由參數 appendfsync 控制,一共3種:
- always:調用系統 fsync 函數,直到同步到硬盤返回;嚴重影響redis性能。
- everysec:先調用 OS write 函數, 寫到緩衝區,而後 redis 每秒執行一次 OS fsync 函數。推薦使用這種方式。
- no: 只執行 write OS 函數,具體同步硬盤策略由 OS 決定;不推薦,數據不安全,容易丟失數據。
4、持久化恢復
AOF 和 RDB 文件均可以用於服務器重啓時的數據恢復,具體流程以下圖:
從圖中能夠看出優先加載 AOF,當沒有 AOF 時才加載 RDB。當 AOF 或者 RDB 存在錯誤,則加載失敗。
5、問題排查和性能優化
Redis 持久化是影響 Redis 性能的高發地,也是面試中常問的問題。
一、fork 操做
當 Redis 作 RDB 或者 AOF 重寫時,必然要進行 fork 操做,對於 OS 來講,fork 都是一個重量級操做。並且,fork 還會拷貝一些數據,雖然不會拷貝主進程全部的物理空間,但會複製主進程的空間內存頁表。對於 10GB 的 Redis 進程,須要複製大約 20MB 的內存頁表,所以 fork 操做耗時跟進程總內存量息息相關,再加上,若是使用虛擬化技術,例如 Xen 虛擬機,fork 會更加耗時。
一個正常的 fork 耗時大概在 20毫秒左右。爲何呢,假設一個 Redis 實例的 OPS 在 5 萬以上,若是 fork 操做耗時在秒級,那麼僵拖慢幾萬條命令的執行,對生產環境影響明顯。
咱們能夠在 Info stats 統計中查詢 latestforkusec 指標獲取最近一次 fork 操做耗時,單位微秒。
如何優化:
- 優先使用物理機或者高效支持 fork 的虛擬化技術,避免使用 Xen。
- 控制 redis 實例最大內存,儘可能控制在 10GB 之內。
- 合理配置 Linux 內存分配策略,避免內存不足致使 fork 失敗。
- 下降 fork 的頻率,如適度放寬 AOF 自動觸發時機,避免沒必要要的全量複製。
二、子進程開銷
fork 完畢以後,會建立子進程,子進程負責 RDB 或者 AOF 重寫,這部分過程主要涉及到 CPU,內存,硬盤三個地方的優化。
- CPU 寫入文件的過程是 CPU 密集的過程,一般子進程對單核 CPU 利用率接近 90%。如何優化呢?既然是 CPU 密集型操做,就不要綁定單核 CPU,由於這樣會和父 CPU 進行競爭。同時,不要和其餘 CPU 密集型服務不是在一個機器上。若是部署了多個 Redis 實例,盡力保證統一時刻只有一個子進程執行重寫工做。
- 內存子進程經過 fork 操做產生,佔用內存大小等同於父進程,理論上須要兩倍的內存完成持久化操做,但 Linux 有 copy on write 機制,父子進程會共享相同的物理內存頁,當父進程處理寫操做時,會把要修改的頁建立對應的副本,而子進程在 fork 操做過程當中,共享整個父進程內存快照。即——若是重寫過程當中存在內存修改操做,父進程負責建立所修改內存頁的副本。這裏就是內存消耗的地方。如何優化呢?儘可能保證同一時刻只有一個子進程在工做;避免大量寫入時作重寫操做。
- 硬盤 硬盤開銷分析:子進程主要職責是將 RDB 或者 AOF 文件寫入硬盤進行持久化,勢必對硬盤形成壓力,可經過工具例如 iostat,iotop 等,分析硬盤負載狀況。
如何優化:
- 不要和其餘高硬盤負載的服務放在一臺機器上,例如 MQ,存儲。
- AOF 重寫時會消耗大量硬盤 IO,能夠開啓配置 no-appendfsync-on-rewrite,默認關閉。表示在 AOF 重寫期間不作 fsync 操做。
- 當開啓 AOF 的 Redis 在高併發場景下,若是使用普通機械硬盤,每秒的寫速率是 100MB左右,這時,Redis 的性能瓶頸在硬盤上,建議使用 SSD。
- 對於單機配置多個 Redis 實例的狀況,能夠配置不一樣實例分盤存儲 AOF 文件,分攤硬盤壓力。
三、AOF 追加阻塞
當開啓 AOF 持久化時,經常使用的同步硬盤的策略是「每秒同步」 everysec,用於平衡性能和數據安全性,對於這種方式,redis 使用另外一條線程每秒執行 fsync 同步硬盤,當系統資源繁忙時,將形成 Redis 主線程阻塞。
流程圖以下:
經過上圖能夠發現:everysec 配置最多可能丟失 2 秒數據,不是 1 秒;若是系統 fsync 緩慢,將會致使 Redis 主線程阻塞影響效率。
問題定位:
- 發生 AOF 阻塞時,會輸入日誌。用於記錄 AOF fsync 阻塞致使拖慢 Redis 服務的行爲。
- 每當 AOF 追加阻塞事件發生時,在 info Persistence 統計中,aofdelayedfsync 指標會累加,查看這個指標方便定位 AOF 阻塞問題。
- AOF 同步最多運行 2 秒的延遲,當延遲發生時說明硬盤存在性能問題,可經過監控工具 iotop 查看,定位消耗 IO 的進程。
四、單機多實例部署
Redis 單線程架構沒法充分利用多核CPU,一般的作法是一臺機器上部署多個實例,當多個實例開啓 AOF 後,彼此之間就會產生CPU 和 IO 的競爭。
如何解決這個問題呢?
讓全部實例的 AOF 串行執行。
咱們經過 info Persistence 中關於 AOF 的信息寫出 Shell 腳本,而後串行執行實例的 AOF 持久化。
整個過程如圖:
經過不斷判斷 AOF 的狀態,手動執行 AOF 重寫,保證 AOF 不會存在競爭。具體的 Shell 編寫以及 info 信息判斷,能夠查看下圖:
6、總結
本文主要講了 Redis 的持久化相關功能,持久化一直是影響 Redis 性能的高發地,也是面試中常常被問到的。包括 RDB 相關的特定和優缺點,AOF 的優缺點,事實上,因爲 RDB 的數據實時性問題,目前用 AOF 比較多了。而持久化恢復也是優先 AOF。
關於持久化的問題排查,就很麻煩了,但無非幾個方面,fork 耗時,子進程的 CPU,內存,硬盤開銷,AOF 的同步阻塞,單機多實例部署。
這些優化,能夠經過前面寫的分析進行排查。