Redis 之持久化
目錄
一.前言
首先,來回顧下前面文章的知識.Redis的特性之一就是讀取速度快,因為它的資料是儲存在記憶體中的,但是這樣還有它的不足之處,那就是當你伺服器斷電時或者程序產生進退後,那麼你所儲存在記憶體中的資料也就蕩然無存了,可是這樣會給我們帶來丟失資料的危險.而Redis正是考慮到了這一點,所以便有了持久化的功能.而持久化的作用正像它的名稱一樣,便是為了保持資料的持久.
Redis的持久化型別有兩種,一種是全量(RDB),一種是增量(AOF),今天這篇文章中便來聊聊這兩種型別的特性和他們的優缺點,以及我們在這兩種型別中如何做選擇.
二.持久化型別之 RDB
1.什麼事RDB?
RDB是把Redis中的完整的資料生成一個快照,然後儲存到硬碟當中,那麼這就是一個RDB檔案了,不過這個RDB檔案是一個二進位制的檔案.當你的Redis服務重啟時,它會去載入這樣的RDB檔案.其作用便是為了備份資料和恢復資料,當然它也是一個複製的媒介,對於Redis的主從複製正式利用這個檔案來完成的.
2.觸發機制
RDB的觸發方式有兩種,分別是:save(同步)和bgsave(非同步).因為save的觸發方式是同步的,那麼它會阻塞當前的Redis伺服器,直到RDB的過程完成為止,如果你的記憶體比較大的話,那麼會造成長時間的阻塞,所以這在生產環境是不建議使用的.而bgsave是非同步的,使用它時Redis的程序會執行fork操作來建立子程序,在RDB持久化的過程便交給子程序去負責了,完成後就回自動結束.對bgsave而言,它的阻塞只會發生在fork階段,時間一般較短,但也有極少的情況下,會阻塞程序.
我們還需要注意以下幾點:
1.save 可以在客戶端顯式觸發,也可以在 shutdown 時自動觸發;bgsave 可以在客戶端顯式觸發,也可以通過配置由定時任務觸發,也可以在 slave 節點觸發.
2.預設執行 shutdown 時,如果沒有開啟 AOF,則自動執行 bgsave
3.因為RDB是全量的,所以每次使用RDB的時候 RDB 檔案都是替換的.
3.RDB的優缺點
優點:
- RDB是緊湊壓縮的二進位制檔案,是Redis某個時間點上的資料快照,比較適合用於備份和全量複製,例如每 6 小時執行 bgsave,儲存到檔案系統之類的.
- Redis 載入 RDB 恢復資料遠遠快於 AOF.
缺點:
- 無法實現到實時持久化/秒級持久化.因為bgsave每次都要執行fork操作子程序,這是重量級操作,執行成本過高.
- 老版本 Redis 無法相容新版本 RDB檔案.
RDB流程圖:
三.持節化型別之AOF
1.什麼事AOF?
AOF是一獨立日誌方式記錄每次命令,其主要作用也是為了解決資料持久化的實時性,目前是Redis持久化的主流方式.
2.AOF的特性
- 使用AOF是需要設定配置:appendonly yes,預設是不開啟的.AOF檔名是通過appendfilename配置的,預設檔名是:appendonly.aof. 儲存的路徑和RDB方式一致,通過dir配置指定.
- AOF每次都是append卸乳命令,因此實時性更高.
- AOF其實並不是直接把資料寫入磁碟檔案中,而是寫在緩衝區(aof_bug)中,這也是為了提高寫入效率,它可以根據不同的策略(always,everysec,no)向磁碟中做同步操作.
- 隨著AOF寫入的檔案越來越大(因為AOF是增量的),所以需要定期對AOF進行重寫,需要進行優化,稱之為“重寫機制”,以達到壓縮的目的.
3.AOF緩衝區同步策略
AOF緩衝區同步策略,由引數 appendfsync 控制,一共3種:
1.alwayss:呼叫sync函式,操作同步到AOF檔案,直到寫入硬碟後返回,這將嚴重影響redis效能.(配置always時,每次都需要同步AOF檔案,一般的SATA硬碟,Redis只有大約幾百的TPS,顯然是與Redis高效能背道而馳的,所以不建議配置)
2.everysec:呼叫系統write 函式,寫入到快取區後,直接返回.而fsync同步檔案操作有專門的執行緒,每秒呼叫一次,推薦配置.(理論上系統宕機也就是丟失下一秒的資料)
3.no: 只執行 write OS 函式,不對AOF檔案做fsync操作同步,具體同步硬碟策略由 OS 決定,通常週期最長為30秒,不推薦,資料不安全,容易丟失資料
.
4.AOF重寫機制
- 執行AOF重寫請求,父程序fork子程序,開銷等同於bgsave.
- 主程序會寫到2個緩衝區,一個是原有的 “AOF 快取區”,一個是專門為子程序準備的 “AOF 重寫緩衝區”,用來儲存部分新資料,防止新的AOF檔案生成期間丟失這部分資料.
- 子程序根據內脣快照,按照命令合併規則寫入到新的AOF檔案,每次寫入是批量的(寫入的資料量可配置aof-rewrite-incremental-fsync),預設是30MB,防止單次刷入的資料量過多,造成阻塞.新的AOF檔案寫入完成後,子程序會通知父程序.
- 父程序吧AOF重寫快取區的資料寫入新的AOF檔案.
- 然後使用新的AOF替換老檔案,至此完成重寫.
重寫流程圖:
四.Redis 持久化型別的抉擇
命令 | RDB | AOF |
---|---|---|
啟動優先順序 | 低 | 高 |
體積 | 小 | 大 |
恢復速度 | 快 | 慢 |
資料安全性 | 丟資料 | 根據策略決定 |
輕重 | 重 | 輕 |
RDB的最佳策略:
- 建議“關”掉RDB(這裡的關用引號,是因為對於Redis的主從複製的全量複製是要我們的主節點執行一次bgsave,然後吧RDB檔案傳給從節點來實現一個複製的過程.)
- 集中管理(雖然RDB是一個很重的操作,但是對於資料備份是有一定作用的,如果按天/小時這樣一個比較大的量級來備份資料,這樣RDB是一個不錯的選擇,因為RDB檔案比較小,這樣傳輸速度會比較快,對於集中管理的備份比較有優勢.
- 主從,從開?因為有時候需要在從節點開一下RDB,這樣可以在本地去儲存這樣一個歷史的RDB檔案,這樣有一定的優勢但是一定要控制他的力度不要是save自動生成的頻率會很頻繁,這樣的話從節點不進入Redis的讀寫,但是所有的Redis都是一個混合部署,就是單機多部署,因為RDB是一個很重的操作,可能仍然對機器本身,例如硬碟/CPU以及記憶體有一定的影響,所以要根據實際開發中的實際需求來進行設定
AOF的最佳策略
- “開”:快取和儲存,在大部分情況先建議開啟AOF,這樣能特別的體現出Redis的一個特點,就是可以實時持久化,並且在大部分情況下只會丟一秒資料,大部分情況下會設定每秒區重新整理磁碟.但是例如有些時候,有些快取的場景,完全使用Redis做快取的功能,其實裡面的資料丟失了,對系統並沒有任何影響,只需要下次載入的時候從資料來源重新載入進來就可以,而且它對資料來源的壓力也沒有那麼大,加入你的訪問對資料來源沒有太大的壓力,這個時候其實是可以關閉掉的.畢竟 AOF確實需要一定開銷的,寫緩衝區等都有一定的開銷的.
- AOF重寫集中管理:單機多部署的情況下AOF集中發生,就是產生大量的fork,但是機器的記憶體比如是16G,我們將會分配百分之六十到七十記憶體給Redis,剩餘20-30來給fork做一個操作用的空間,但是這部分空間並不是很大的,假如集中做fork,就可能出現記憶體爆滿,會出現swap的情況.
- everysec(每秒1是重新整理)
最佳策略:小分片,快取或者儲存,監控(硬碟,記憶體,負載,網路),足夠記憶體
五.持久化的恢復
RDB 和 AOF 檔案都可以用於伺服器重啟時來做資料恢復,具體恢復流程如圖:
六.持久化問題的分析定位與優化
Redis持久化的功能一直是影響Redis效能的高發地,這也是我們日常工作與面試中常遇到的.
1.fork操作
當Redis做 RDB 或者 AOF 重寫時,必不可少的是要進行 fork 操作,對於 大多數作業系統 來說,fork 都是一個重量級操作.雖然不會拷貝父程序所有的物理空間,但會複製父程序的空間記憶體頁表.對於 10GB 的 Redis 程序,需要複製大約 20MB 的記憶體頁表,因此 fork 操作耗時跟程序總記憶體量息息相關,如果還使用虛擬化技術,例如 Xen 虛擬機器,fork 操作會更加耗時.
對於一個 Redis 例項的 OPS 在 5 萬以上,如果 fork 操作耗時在秒級,那麼將會拖慢幾萬條命令的執行,對生產環境影響明顯.在正常情況下,fork操作的耗時應該是1GB/20ms左右,這個可以在 Info stats 統計中查詢 latest_fork_usec 指標獲取最近一次 fork 操作耗時,單位微秒.
優化方案:
- 優先使用物理機或者高效支援 fork 的虛擬化技術,避免使用 Xen.
- 控制 redis 例項最大可用記憶體,foek耗時跟記憶體量成正比,所以線上建議控制實力記憶體在 10GB 以內.
- 合理配置 Linux 記憶體分配策略,避免記憶體不足導致 fork 失敗.
- 降低 fork操作 的頻率,如適度放寬 AOF 自動觸發時機,避免不必要的全量複製.
2.子程序開銷和優化
fork 完畢之後,會建立子程序,子程序會負責 RDB 或者 AOF 重寫,這部分過程主要涉及到 CPU,記憶體,硬碟三個地方的優化.
1)cpu
cpu開銷分析與優化
子程序負責吧程序內的資料分批寫入檔案,這個寫入檔案的過程是 CPU 密集的過程,通常子程序對單核 CPU 利用率接近 90%. 優化方法:Redis是 CPU 密集型服務,不要繫結單核 CPU,由於子程序會非常消耗CPU,所以這樣會和父 CPU 進行競爭.同時,不要和其他 CPU 密集型服務部署在一個機器上。如果部署了多個 Redis 例項,盡力保證統一時刻只有一個子程序執行重寫工作.
2)記憶體
子程序通過 fork 操作產生,佔用記憶體大小等同於父程序,理論上需要兩倍的記憶體完成持久化操作,但 Linux 有複製機制 (copy on write ).父子程序會共享相同的實體記憶體頁,當父程序處理寫操作時,會把要修改的頁建立對應的副本,而子程序在 fork 操作過程中,共享整個父程序記憶體快照. 如果重寫過程中存在記憶體修改操作,父程序負責建立所修改記憶體頁的副本.這裡就是記憶體消耗的地方. 優化方法:和cpu一樣,如果部署多個Redis例項,儘量保證同一時刻只有一個子程序在工作;避免大量寫入時做子程序重寫操作,這樣會導致父程序維護大量的快照副本,造成記憶體消耗.
3)硬碟開銷分析
程序主要職責是將 RDB 或者 AOF 檔案寫入硬碟進行持久化,勢必造成對硬碟造成壓力,可通過工具例如 iostat,iotop 等工具分析重寫期間硬碟負載情況.
優化方法:
(a).不要和其他高硬碟負載的服務放在一臺機器上,例如 MQ,儲存服務.
(b)AOF 重寫時會消耗大量硬碟 IO,可以開啟配置 no-appendfsync-on-rewrite,預設關閉。表示在 AOF 重寫期間不做 fsync 操作.
(c)當開啟 AOF 的 Redis 在高併發場景下,如果使用普通機械硬碟,每秒的寫速率是 100MB左右,這時,Redis 的效能瓶頸在硬碟上,建議使用 SSD.
(d)對於單機配置多個 Redis 例項的情況,可以配置不同例項分盤儲存 AOF 檔案,分攤硬碟的寫入壓力.
3. AOF 追加阻塞
當開啟 AOF 持久化時,常用的同步硬碟的策略是everysec,用於平衡效能和資料安全性.對於這種方式,Redis 使用另一條執行緒每秒執行 fsync 同步硬碟.當系統資源繁忙時,將造成 Redis 主執行緒阻塞.
如圖所示:
從上圖中可以發現:everysec 配置最多可能丟失 2 秒資料,不是 1 秒;如果系統 fsync 緩慢,將會導致 Redis 主執行緒阻塞影響效率.
問題定位:
- 發生 AOF 阻塞時,會輸入日誌。用於記錄 AOF fsync 阻塞導致拖慢 Redis 服務的行為.
- 每當 AOF 追加阻塞事件發生時,在 info Persistence 統計中,aof_delayed_fsync 指標會累加,檢視這個指標方便定位 AOF 阻塞問題.
- AOF 同步最多執行 2 秒的延遲,當延遲發生時說明硬碟存在效能問題,可通過監控工具 iotop 檢視,定位消耗 IO 的程序.
4. 單機多例項部署
Redis 單執行緒架構無法充分利用多核CPU,通常的做法是一臺機器上部署多個例項,當多個例項開啟 AOF 後,彼此之間就會產生CPU 和 IO 的競爭.
解決方法:讓所有例項的 AOF 序列執行.我們通過 info Persistence 中關於 AOF 的資訊寫出 Shell 指令碼,然後序列執行例項的 AOF 持久化.
info Persistence片段度量指標表:
屬性名 |
屬性值 |
---|---|
rdb_bgsave_in_progress | bgsave子程序是否正在執行 |
rdb_current_bgsave_time_sec | 當前執行bgsave的時間,-1表示未執行 |
aof_enabled | 是否開啟AOF功能 |
aof_rewrite_in_progress | AOF重寫子程序是否正在執行 |
aof_rewrite_scheduled | 在bgsave結束後是否執行AOF重寫 |
aof_current_rewrite_time_sec | 當前執行AOF重寫的時間,-1表示未執行 |
aof_current_size | AOF檔案當前位元組數 |
aof_base_size | AOF上次重寫rewrite位元組數 |
基於以上指標,可以通過外部輪詢控制AOF的重寫操作的執行,整個過程如圖:
七.回顧總結
本文講了 Redis 的持久化相關功能,例如持久化的型別,持久化每種型別的優缺點,Redis 持久化型別的選擇,持久化溼如何恢復的,還有持久化問題的分析定位與優化.
參考:《redis開發與運維》,《深入分散式快取》
版權宣告:尊重博主原創文章,轉載請註明出處 https://blog.csdn.net/zfy163520