前面用了3篇文章介紹了一些底層實現和工程架構相關的問題,鑑於Redis的熱點問題仍是比較多的,所以今天繼續來看工程架構相關的問題,感興趣的能夠先回顧一下以前的3篇文章,以下:
【決戰西二旗】|Redis面試熱點之底層實現篇
【決戰西二旗】|Redis面試熱點之底層實現篇(續)
【決戰西二旗】|Redis面試熱點之工程架構篇面試
經過本文你將瞭解到如下內容:segmentfault
Q:談談你對Redis數據同步(複製)的理解吧!後端
理解持久化和數據同步的關係,須要從單點故障和高可用兩個角度來分析:數組
假如咱們如今只有一臺做爲緩存的Redis機器,經過持久化將熱點數據寫到磁盤,某時刻該Redis單點機器發生故障宕機,此期間緩存失效,主存儲服務將承受全部的請求壓力倍增,監控程序將宕機Redis機器拉起。緩存
重啓以後,該機器能夠Load磁盤RDB數據進行快速恢復,恢復的時間取決於數據量的多少,通常秒級到分鐘級不等,恢復完成保證以前的熱點數據還在,這樣存儲系統的CacheMiss就會下降,有效下降了緩存擊穿的影響。服務器
在單點Redis中持久化機制很是有用,只寫文字容易讓你們睡着,我畫了張圖:網絡
做爲一個高可用的緩存系統單點宕機是不容許的,所以就出現了主從架構,對主節點的數據進行多個備份,若是主節點掛點,能夠馬上切換狀態最好的從節點爲主節點,對外提供寫服務,而且其餘從節點向新主節點同步數據,確保整個Redis緩存系統的高可用。架構
如圖展現了一個一主兩從讀寫分離的Redis系統主節點故障遷移的過程,整個過程並無中止正常工做,大大提升了系統的高可用:併發
從上面的兩點分析能夠得出個小結論【劃重點】:
持久化讓單點故障再也不可怕,數據同步爲高可用插上翅膀。異步
咱們理解了數據同步對Redis的重要做用,接下來繼續看數據同步的實現原理和過程、重難點等細節問題吧!
對分佈式存儲有了解的讀者必定知道CAP理論,說來慚愧筆者在2018年3月份換工做的時候,去Face++曠視科技面後端開發崗位時就遇到了CAP理論,除了CAP理論問題以外其餘問題都在射程內,因此最終仍是拿了Offer。
可是印象很深T大畢業的面試官說前面的問題答得都不錯,爲啥CAP問題答得這麼菜…其實我當時只知道CAP理論就像高富帥同樣,不那麼容易達到...細節不清楚...各位吃瓜讀者,筆者前面說這個小事情的目的是想表達:CAP理論對於理解分佈式存儲很是重要,下回大家面試被問到CAP別怪我沒提醒。
在理論計算機科學中,CAP定理又被稱做布魯爾定理Brewer's theorem,這個定理起源於加州大學伯克利分校的計算機科學家埃裏克·布魯爾在2000年的分佈式計算原理研討會PODC上提出的一個猜測。
在2002年麻省理工學院的賽斯·吉爾伯特和南希·林奇發表了布魯爾猜測的證實,使之成爲一個定理。它指出對於一個分佈式計算系統來講,不可能同時知足如下三點:
來看一張阮一峯大佬畫的圖:
舉個簡單的例子,說明一下CP和AP的兼容性:
CP和AP問題
理解CP和AP的關鍵在於分區容忍性P,網絡分區在分佈式存儲中再日常不過了,即便機器在一個機房,也不可能全都在一個機架或一臺交換機。
這樣在局域網就會出現網絡抖動,筆者作過1年多DPI對於網絡傳輸中最深入的三個名詞:丟包、亂序、重傳。因此咱們看來風平浪靜的網絡,在服務器來講多是風大浪急,一不當心就不通了,因此當網絡出現斷開時,這時就出現了網絡分區問題。
對於Redis數據同步而言,假設從結點和主結點在兩個機架上,某時刻發生網絡斷開,若是此時Redis讀寫分離,那麼從結點的數據必然沒法與主繼續同步數據。在這種狀況下,若是繼續在從結點讀取數據就形成數據不一致問題,若是強制保證數據一致從結點就沒法提供服務形成不可用問題,從而看出在P的影響下C和A沒法兼顧。
其餘幾種狀況就不深刻了,從上面咱們能夠得出結論:當Redis多臺機器分佈在不一樣的網絡中,若是出現網絡故障,那麼數據一致性和服務可用性沒法兼顧,Redis系統對此必須作出選擇,事實上Redis選擇了可用性,或者說Redis選擇了另一種最終一致性。
最終一致性
Redis選擇了最終一致性,也就是不保證主從數據在任什麼時候刻都是一致的,而且Redis主從同步默認是異步的,親愛的盆友們不要暈!不要蒙圈!
我來一下解釋同步複製和異步複製(注意:考慮讀者的感覺 我並無寫成同步同步和異步同步 哈哈):
一圖勝千言,看紅色的數字就知道同步複製和異步複製的區別了:
Redis選擇異步複製能夠避免客戶端的等待,更符合現實要求,不過這個複製方式能夠修改,根據本身需求而定吧。
從從複製
假如Redis高可用系統中有一主四從,若是四個從同時向主節點進行數據同步,主節點的壓力會比較大,考慮到Redis的最終一致性,所以Redis後續推出了從從複製,從而將單層複製結構演進爲多層複制結構,筆者畫了個圖看下:
全量複製是從結點由於故障恢復或者新添加從結點時出現的初始化階段的數據複製,這種複製是將主節點的數據所有同步到從結點來完成的,因此成本大但又不可避免。
增量複製是主從結點正常工做以後的每一個時刻進行的數據複製方式,涓涓細流同步數據,這種同步方式又輕又快,優勢確實很多,不過若是沒有全量複製打下基礎增量複製也沒戲,因此兩者不是矛盾存在而是相互依存的。
Redis的全量複製過程主要分三個階段:
借鑑參考1的一張圖表,寫的很好,我就再也不重複畫圖了:
考慮一個多從併發全量複製問題:
若是此時有多個從結點同時向主結點發起全量同步請求會怎樣?
Redis主結點是個聰明又誠實的傢伙,好比如今有3個從結點A/B/C陸續向主節點發起SYNC全量同步請求。
再考慮一個快照複製循環問題:
主節點執行bgsave是比較耗時且耗內存的操做,期間從結點也經歷裝載舊數據->釋放內存->裝載新數據的過程,內存先升後降再升的動態過程,從而知道不管主節點執行快照仍是從結點裝載數據都是須要時間和資源的。
拋開對性能的影響,試想若是主節點快照時間是1分鐘,在期間有1w條新命令到來,這些新命令都將寫到緩衝區,若是緩衝區比較小隻有8k,那麼在快照完成以後,主節點緩衝區也只有8k命令丟失了2k命令,那麼此時從結點進行全量同步就缺失了數據,是一次錯誤的全量同步。
無奈之下,從結點會再次發起SYNC命令,從而陷入循環,所以緩衝區大小的設置很重要,二話不說再來一張圖:
增量複製過程稍微簡單一些,可是很是有用,試想複雜的網絡環境下,並非每次斷開都沒法恢復,若是每次斷開恢復後就要進行全量複製,那豈不是要把主節點搞死,因此增量複製算是對複雜網絡環境下數據複製過程的一個優化,容許一段時間的落後,最終追上就行。
增量複製是個典型的生產者-消費者模型,使用定長環形數組(隊列)來實現,若是buffer滿了那麼新數據將覆蓋老數據,所以從結點在複製數據的同時向主節點反饋本身的偏移量,從而確保數據不缺失。
這個過程很是好理解,kakfa這種MQ也是這樣的,因此在合理設置buffer大小的前提下,理論上從的消費能力是大於主的生產能力的,大部分只有在網絡斷開時間過長時會出現buffer被覆蓋,從結點消費滯後的狀況,此時只能進行全量複製了。
理解無盤複製以前先看下什麼是有盤複製呢?
所謂盤是指磁盤,多是機械磁盤或者SSD,可是不管哪種相比內存都更慢,咱們都知道IO操做在服務端的耗時是佔大頭的,所以對於全量複製這種高IO耗時的操做來講,尤爲當服務併發比較大且還在進行其餘操做時對Redis服務自己的影響是比較大大,以前的模式時這樣的:
在Redis2.8.18版本以後,開發了無盤複製,也就是避免了生成的RDB文件落盤再加載再網絡傳輸的過程,而是流式的遍歷發送過程,主節點一邊遍歷內存數據,一邊將數據序列化發送給從結點,從結點沒有變化,仍然將數據依次存儲到本地磁盤,完成傳輸以後進行內存加載,可見無盤複製是對IO更友好。
時間緣由只能寫這麼多了,和你們一塊兒學習不是把桶填滿而是把火點燃。
回顧一下:本文主要講述了持久化和數據同步的關係、Redis分佈式存儲的CAP選擇、Redis數據同步複製和異步複製、全量複製和增量複製的原理、無盤複製等,相信耐心的讀者必定會有所收穫的。
最後能夠思考一個問題:
Redis的數據同步仍然會出現數據丟失的狀況,好比主節點往緩衝區寫了10k條操做命令,此時主掛掉了,從結點只消費了9k操做命令,那麼切主以後從結點的數據就丟失了1k,即便舊主節點恢復也只能做爲從節點向新主節點發起全量複製,那麼咱們該如何優化這種狀況呢?