歡迎關注我的公衆號:石杉的架構筆記(ID:shishan100)mysql
週一至週五早8點半!精品技術文章準時送上!面試
上篇文章(《億級流量系統架構之如何設計每秒十萬查詢的高併發架構》),聊了一下系統架構中的查詢平臺。
算法
咱們採用冷熱數據分離:sql
最終,整套查詢架構抗住每秒10萬的併發查詢請求,都沒問題。數據庫
本文做爲這個架構演進系列的最後一篇文章,咱們來聊聊高可用這個話題。所謂的高可用是啥意思呢?緩存
簡單來講,就是如此複雜的架構中,任何一個環節均可能會故障,好比MQ集羣可能會掛掉、KV集羣可能會掛掉、MySQL集羣可能會掛掉。那你怎麼才能保證說,你這套複雜架構中任何一個環節掛掉了,整套系統能夠繼續運行?性能優化
這就是所謂的全鏈路99.99%高可用架構,由於咱們的平臺產品是付費級別的,付費級別,必需要爲客戶作到最好,可用性是務必要保證的!架構
咱們先來看看目前爲止的架構是長啥樣子的。併發
異步轉同步 + 限流算法 + 限制性丟棄流量框架
MQ集羣故障實際上是有機率的,並且挺正常的,由於以前就有的大型互聯網公司,MQ集羣故障以後,致使全平臺幾個小時都沒法交易,嚴重的會形成幾個小時公司就有數千萬的損失。咱們以前也遇到過MQ集羣故障的場景,可是並非這個系統裏。
你們想一下,若是這個鏈路中,萬一MQ集羣故障了,會發生什麼?
看看右上角那個地方,數據庫binlog採集中間件就沒法寫入數據到MQ集羣了啊,而後後面的流控集羣也沒法消費和存儲數據到KV集羣了。這套架構將會完全失效,沒法運行。
這個是咱們想要的效果嗎?那確定不是的,若是是這樣的效果,這個架構的可用性保障也太差了。
所以在這裏,咱們針對MQ集羣的故障,設計的高可用保障方案是:異步轉同步 + 限流算法 + 限制性丟棄流量。
簡單來講,數據庫binlog採集環節一旦發現了MQ集羣故障,也就是嘗試屢次都沒法寫入數據到MQ集羣,此時就會觸發降級策略。再也不寫入數據到MQ集羣,而是轉而直接調用流控集羣提供的備用流量接收接口,直接發送數據給流控集羣。
可是流控集羣也比較尷尬,以前用MQ集羣就是削峯的啊,高峯期能夠稍微積壓一點數據在MQ集羣裏,避免流量過大,沖垮後臺系統。
因此流控集羣的備用流量接收接口,都是實現了限流算法的,也就是若是發現一旦流量過大超過了閾值,直接採起丟棄的策略,拋棄部分流量。
可是這個拋棄部分流量也是有講究的,你要怎麼拋棄流量?若是你無論三七二十一,胡亂丟棄流量,可能會致使全部的商家看到的數據分析結果都是不許確的。所以當時選擇的策略是,僅僅選擇少許商家的數據全量拋棄,可是大部分商家的數據全量保存。
也就是說,好比你的平臺用戶有20萬吧,可能在這個丟棄流量的策略下,有2萬商家會發現看不到今天的數據了,可是18萬商家的數據是不受影響,都是準確的。可是這個總比20萬商家的數據所有都是不許確的好吧,因此在降級策略制定的時候,都是有權衡的。
這樣的話,在MQ集羣故障的場景下,雖然可能會丟棄部分流量,致使最終數據分析結果有誤差,可是大部分商家的數據都是正常的。
你們看看下面的圖,高可用保障環節所有選用淺紅色來表示,這樣很清晰。
臨時擴容Slave集羣 + 內存級分片存儲 + 小時級數據粒度
下一個問題,若是KV集羣掛了怎麼辦?這個問題咱們還真的遇到過,不過也不是在這個系統裏,是在另一個咱們負責過的核心繫統裏,KV集羣確實出過故障,直接從持續好多個小時,致使公司業務都幾近於停擺,損失也是幾千萬級別的。
你們看看那個架構圖的右側部分,若是KV集羣掛了咋辦?那也是災難性的,由於咱們的架構選型裏,直接就是基於kv集羣來進行海量數據存儲的,要是KV掛了,沒任何高可用保障措施的話,會致使流控集羣沒法把數據寫入KV集羣,此時後續環節就沒法繼續計算了。
咱們當時考慮過要不要引入另一套存儲進行雙寫,好比引入一套hbase集羣,可是那樣依賴會搞的更加的複雜,打鐵還需自身硬,仍是要從自身架構來作優化。
所以,當時選擇的一套kv集羣降級的預案是:臨時擴容Slave集羣 + 小時級數據粒度 + 內存級分片存儲。
簡單來講,就是一旦發現kv集羣故障,直接報警。咱們收到報警以後,就會立馬啓動臨時預案,手動擴容部署N倍的Slave計算集羣。
接着一樣會手動打開流控集羣的一個降級開關,而後流控集羣會直接按照預設的hash算法分發數據到各個Slave計算節點。
這就是關鍵點,不要再基於kv集羣存數據了,自己咱們的Slave集羣就是分佈式計算的,那不是恰好能夠臨時用做分佈式存儲嗎!直接流控集羣分發數據到Slave集羣就好了,Slave節點將數據留存在內存中便可。
而後Master節點在分發數據計算任務的時候,會保證計算任務分發到某個Slave節點以後,他只要基於本地內存中的數據計算便可。
將Master節點和Slave節點都重構一下,重構成本不會過高,可是這樣就實現了本地數據存儲 + 本地數據計算的效果了。
可是這裏一樣有一個問題,要知道當日數據量但是很大的!若是你都放Slave集羣內存裏還得了?
因此說,既然是降級,又要作一個balance了。咱們選擇的是小時級數據粒度的方案,也就是說,僅僅在Slave集羣中保存最近一個小時的數據,而後計算數據指標的時候,只能產出每一個小時的數據指標。
可是若是是針對一天的數據須要計算出來的數據指標,此時降級事後就沒法提供了,由於內存中永遠只有最近一個小時的數據,這樣才能保證Slave集羣的內存不會被撐爆。
對用戶而言,就是隻能看當天每一個小時的數據指標,可是全天彙總的暫時就沒法看到。
計算任務重分配 + 主備切換機制
下一塊就是實時計算鏈路的高可用保障方案了,其實這個以前給你們說過了,實時計算鏈路是一個分佈式的架構,因此要麼是Slave節點宕機,要麼是Master節點宕機。
其實這個倒沒什麼,由於Slave節點宕機,Master節點感知到了,會從新分配計算任務給其餘的計算節點;若是Master節點宕機,就會基於Active-Standby的高可用架構,自動主備切換。
我們直接把架構圖裏的實時計算鏈路中的高可用環節標成紅色就能夠了。
自研緩存集羣查詢引擎 + JVM本地緩存 + 限流機制
接着我們來看左側的數據查詢那塊,熱數據也就是提供實時計算鏈路寫入當日數據的計算結果的,用的是MySQL集羣來承載主體數據,而後前面掛載一個緩存集羣。
若是出現故障,只有兩種狀況:一種是MySQL集羣故障,一種是緩存集羣故障。
我們分開說,若是是MySQL集羣故障,咱們採起的方案是:實時計算結果直接寫入緩存集羣,而後由於沒有MySQL支撐,因此無法使用SQL來從MySQL中組裝報表數據。
所以,咱們自研了一套基於緩存集羣的內存級查詢引擎,支持簡單的查詢語法,能夠直接對緩存集羣中的數據實現條件過濾、分組聚合、排序等基本查詢語義,而後直接對緩存中的數據查詢分析事後返回。
可是這樣惟一的很差,就是緩存集羣承載的數據量遠遠沒有MySQL集羣大,因此會致使部分用戶看不到數據,部分用戶能夠看到數據。不過這個既然是降級 ,那確定是要損失掉部分用戶體驗的。
若是是緩存集羣故障,咱們會有一個查詢平臺裏的本地緩存,使用ehcache等框架就能夠實現,從mysql中查出來的數據在查詢平臺的jvm本地緩存裏cache一下,也能夠用做必定的緩存支撐高併發的效果。並且查詢平臺實現限流機制,若是查詢流量超過自身承載範圍,就限流,直接對查詢返回異常響應。
收集查詢日誌 + 離線日誌分析 + 緩存高頻查詢
其實你們看上面的圖就知道,冷數據架構自己就比比較複雜,涉及到ES、HBase等東西,若是你要是想作到一點ES、HBase宕機,而後還搞點兒什麼降級方案,仍是挺難的。
你總不能ES不能用了,臨時走Solr?或者HBase不能用了,臨時走KV集羣?都不行。那個實現複雜度過高,不合適。
因此當時咱們採起的方法就是,對最近一段時間用戶發起的離線查詢的請求日誌進行收集,而後對請求日誌在天天凌晨進行分析,分析出來那種每一個用戶會常常、屢次、高頻發起的冷數據查詢請求,而後對這個特定的查詢(好比特殊的一組條件,時間範圍,維度組合)對應的結果,進行緩存。
這樣就直接把各個用戶高頻發起的冷數據查詢請求的結果天天動態分析,動態放入緩存集羣中。好比有的用戶天天都會看一下上週一週的數據分析結果,或者上個月一個月的數據分析結果,那麼就能夠把這些結果提早緩存起來。
一旦ES、HBase等集羣故障,直接對外冷數據查詢,僅僅提供這些提早緩存好的高頻查詢便可,非高頻無緩存的查詢結果,就是看不到了。
上述系統到目前爲止,已經演進到很是不錯的狀態了,由於這套架構已經解決了百億流量高併發寫入,海量數據存儲,高性能計算,高併發查詢,高可用保障,等一系列的技術挑戰。線上生產系統運行很是穩定,足以應對各類生產級的問題。
其實再日後這套系統架構還能夠繼續演進,由於大型系統的架構演進,能夠持續N多年,好比咱們後面還有分佈式系統全鏈路數據一致性保障、高穩定性工程質量保障,等等一系列的事情,不過文章就再也不繼續寫下去了,由於文章承載內容量太少,很難寫清楚全部的東西。
其實有很多同窗跟我反饋說,感受看不懂這個架構演進系列的文章,其實很正常,由於文章承載內容較少,這裏有大量的細節性的技術方案和落地的實施,都無法寫出來,只能寫一下大型系統架構不斷演進,解決各類線上技術挑戰的一個過程。
我以爲對於一些年輕的同窗,主要仍是瞭解一下系統架構演進的過程,對於一些年長已經作架構設計的兄弟,應該能夠啓發一些思路,歡迎公衆號後臺給我留言,探討這些技術問題。
一大波微服務、分佈式、高併發、高可用的原創系列
文章正在路上,歡迎掃描下方二維碼,持續關注:
石杉的架構筆記(id:shishan100)
十餘年BAT架構經驗傾囊相授