給你一份精心設(shè)計(jì)的消息中間件高擴(kuò)展架構(gòu),趕緊寫進(jìn)簡(jiǎn)歷吧
1、寫在前面
本文咱們來聊聊如何通過 MQ 消息中間件的使用,重構(gòu)系統(tǒng)之間的耦合,讓系統(tǒng)具備高度的可擴(kuò)展性。
首先看一張系統(tǒng)之間的耦合圖,大家先不用關(guān)注圖中數(shù)據(jù)查詢平臺(tái)和實(shí)時(shí)計(jì)算平臺(tái)的具體細(xì)節(jié)。
只需知道這里的數(shù)據(jù)查詢平臺(tái)和實(shí)時(shí)計(jì)算平臺(tái)兩個(gè)系統(tǒng),通過一套共享存儲(chǔ)(數(shù)據(jù)庫集群+緩存集群)進(jìn)行了耦合。
2、劃分系統(tǒng)邊界
只要有耦合,一旦要解決耦合,那么第一個(gè)要干的事就是先劃分清楚系統(tǒng)之間的邊界。
比如上面那兩套系統(tǒng)都共享了一套存儲(chǔ)集群,大家先思考一下,兩個(gè)系統(tǒng)之間的邊界應(yīng)該如何劃分?
換句話說,中間那套緩存集群和數(shù)據(jù)庫集群,應(yīng)該屬于哪個(gè)系統(tǒng)?要回答這個(gè)問題,主要就是考慮緩存集群和數(shù)據(jù)庫集群主要是給誰用的?
答案顯而易見,當(dāng)然是給數(shù)據(jù)查詢平臺(tái)用的。
說白了,緩存集群和數(shù)據(jù)庫集群都是數(shù)據(jù)查詢平臺(tái)賴以生存的核心底層數(shù)據(jù)存儲(chǔ),它們存儲(chǔ)的數(shù)據(jù)也都是屬于數(shù)據(jù)查詢平臺(tái)的核心數(shù)據(jù)。
對(duì)于實(shí)時(shí)計(jì)算平臺(tái)來說,他只不過是將自己計(jì)算后的結(jié)果寫入到緩存集群和數(shù)據(jù)庫集群罷了。
實(shí)時(shí)計(jì)算平臺(tái)只要寫入過后,后續(xù)就不會(huì)再管那些數(shù)據(jù)了,所以這兩套集群明顯是不屬于實(shí)時(shí)計(jì)算平臺(tái)的。
系統(tǒng)間的邊界劃分清楚之后,從整體架構(gòu)來看,兩套系統(tǒng)間的關(guān)系應(yīng)該是下面這樣:
3、引入消息中間件解耦
現(xiàn)在我們劃分清楚了系統(tǒng)之間的邊界,接著下一步,就是引入消息中間件來進(jìn)行解耦。
如果對(duì)消息中間件的使用場(chǎng)景還不太熟悉的朋友,可以先看看之前的文章:《為什么要使用MQ消息中間件?這幾個(gè)問題必須拿下!》,里面對(duì)消息中間件的各種使用場(chǎng)景都有詳細(xì)闡述。
現(xiàn)在我們只要引入一個(gè)消息中間件,然后讓實(shí)時(shí)計(jì)算平臺(tái)將計(jì)算好的數(shù)據(jù)按照預(yù)設(shè)的格式直接寫入到消息中間件即可。
同時(shí)在數(shù)據(jù)查詢平臺(tái)這邊增加一個(gè)數(shù)據(jù)接入服務(wù),負(fù)責(zé)將消息中間件里的數(shù)據(jù)消費(fèi)出來,然后落地寫入到本地的緩存集群和數(shù)據(jù)庫集群
整個(gè)過程如下圖所示:
通過上圖可以清晰的看到,兩個(gè)系統(tǒng)之間已經(jīng)不再直接基于共享數(shù)據(jù)存儲(chǔ)進(jìn)行耦合了,中間加入了MQ消息中間件,它僅僅是用于兩個(gè)系統(tǒng)之間的數(shù)據(jù)交互和傳輸,職責(zé)簡(jiǎn)單,清晰明了。
這樣做最大的好處:數(shù)據(jù)查詢平臺(tái)可以對(duì)涌入自身平臺(tái)的數(shù)據(jù),按照自己的需求進(jìn)行定制化的管控,不會(huì)像之前那樣的被動(dòng)。
因?yàn)橛咳霐?shù)據(jù)查詢平臺(tái)的所有數(shù)據(jù),都需要經(jīng)過數(shù)據(jù)接入服務(wù)那一關(guān),在數(shù)據(jù)接入服務(wù)那里就可以隨意根據(jù)自己的情況進(jìn)行管理。
4、利用消息中間件削峰填谷
好,我們繼續(xù),現(xiàn)在把目光集中到兩個(gè)系統(tǒng)上,進(jìn)行痛點(diǎn)分析。
兩個(gè)系統(tǒng)間第一大痛點(diǎn):實(shí)時(shí)計(jì)算平臺(tái)會(huì)高并發(fā)寫入數(shù)據(jù)查詢平臺(tái),之前不做任何管控的時(shí)候,導(dǎo)致各種意外發(fā)生。
比如快速增長(zhǎng)的寫庫壓力導(dǎo)致數(shù)據(jù)查詢平臺(tái)必須優(yōu)先cover住分庫分表那塊的架構(gòu),打破自己的架構(gòu)演進(jìn)節(jié)奏。
比如突然意外出現(xiàn)的熱數(shù)據(jù)因?yàn)椴蛔鋈魏螌懭牍芸?,一下子可能把?shù)據(jù)庫服務(wù)器擊垮。
因此一旦用消息中間件在中間擋了一層之后,就可以進(jìn)行削峰填谷了。那什么叫削峰填谷呢?
很簡(jiǎn)單,如果不做任何管控,實(shí)時(shí)計(jì)算平臺(tái)并發(fā)寫入數(shù)據(jù)庫集群,在高峰期會(huì)有一個(gè)陡然上升的尖峰。
打個(gè)比方:平時(shí)每秒寫入并發(fā)就500,但是高峰期寫入并發(fā)請(qǐng)求有5000,那么就會(huì)突然冒出來一個(gè)尖峰,此時(shí)數(shù)據(jù)查詢平臺(tái)的數(shù)據(jù)庫集群可能就會(huì)受不了。
那如果我們?cè)跀?shù)據(jù)接入服務(wù)里做一個(gè)限流控制,效果會(huì)怎么樣呢?
也就是說,在數(shù)據(jù)接入服務(wù)里,根據(jù)當(dāng)前數(shù)據(jù)查詢平臺(tái)的數(shù)據(jù)庫集群能承載的并發(fā)上限進(jìn)行控制。
比如最多承載每秒3000,那么數(shù)據(jù)接入服務(wù)自己就控制好,每秒最多就往自己本地的數(shù)據(jù)庫集群里寫入每秒3000的請(qǐng)求,此時(shí)就會(huì)出現(xiàn)削峰填谷的效果。
雖然說在實(shí)時(shí)計(jì)算那邊,高峰期瞬時(shí)寫入壓力最大有5000/s,但是數(shù)據(jù)接入服務(wù)做了流量控制,最多就往本地?cái)?shù)據(jù)庫集群寫入3000/s。
然后每秒就會(huì)有2000條數(shù)據(jù)在消息中間件里做一個(gè)積壓,但是積壓一會(huì)兒不要緊,最起碼保證在高峰期,我們把這個(gè)向上的尖峰給削平,這就是削峰。
高峰期過了之后,現(xiàn)在可能就100/s的寫入壓力,但是此時(shí)數(shù)據(jù)接入服務(wù)會(huì)持續(xù)不斷的從消息中間件里取出來數(shù)據(jù),然后持續(xù)以最大3000/s的寫入壓力往本地?cái)?shù)據(jù)庫集群里寫入。
那么在低峰期,我們可以看到還會(huì)持續(xù)一段時(shí)間是3000/s的寫入速度往本地?cái)?shù)據(jù)庫里寫,原來的低峰期是谷底,現(xiàn)在谷底被填平了,這就是所謂的填谷。
通過這套削峰填谷的機(jī)制,可以保證數(shù)據(jù)查詢平臺(tái)以自己能接受的速率,均勻的把MQ里的數(shù)據(jù)拿出來寫入自己本地?cái)?shù)據(jù)庫集群中。
這樣無論實(shí)時(shí)計(jì)算平臺(tái)多高的并發(fā)請(qǐng)求壓力過來,哪怕是那種異常的熱數(shù)據(jù),瞬間上萬并發(fā)請(qǐng)求過來也無所謂了。因?yàn)镸Q中間件可以抗住瞬間高并發(fā)寫入,數(shù)據(jù)查詢平臺(tái)永遠(yuǎn)都是穩(wěn)定勻速的寫入自己本地?cái)?shù)據(jù)庫。
這樣一來,數(shù)據(jù)查詢平臺(tái)就不需要去過多的care實(shí)時(shí)計(jì)算平臺(tái)帶給自己的壓力了,可以按照自己的節(jié)奏進(jìn)行各種架構(gòu)迭代。
此時(shí)的架構(gòu)圖如下所示,在數(shù)據(jù)接入服務(wù)中多了一個(gè)限流的模塊。
5、手動(dòng)流量開關(guān)配合數(shù)據(jù)庫運(yùn)維
通過消息中間件將兩個(gè)系統(tǒng)隔離的另一大好處:數(shù)據(jù)查詢平臺(tái)做任何數(shù)據(jù)運(yùn)維的操作,比如DDL、分庫分表擴(kuò)容、數(shù)據(jù)遷移,等等,已經(jīng)跟實(shí)時(shí)計(jì)算平臺(tái)徹底無關(guān)了。實(shí)時(shí)計(jì)算平臺(tái)主要簡(jiǎn)單的往消息中間件寫入,其他的就不用管了。
現(xiàn)在數(shù)據(jù)查詢平臺(tái)如果要做一些數(shù)據(jù)庫運(yùn)維的操作,就可以通過在數(shù)據(jù)接入服務(wù)中加入一個(gè)手動(dòng)流量開關(guān),臨時(shí)將流量開關(guān)關(guān)閉一會(huì)兒。比如選擇午睡這種相對(duì)低峰的時(shí)期,半小時(shí)內(nèi)關(guān)閉流量開關(guān)。
然后此時(shí)數(shù)據(jù)接入服務(wù)就不會(huì)繼續(xù)往本地?cái)?shù)據(jù)庫寫入數(shù)據(jù)了,此時(shí)寫入操作就會(huì)停止,半小時(shí)內(nèi)迅速完成數(shù)據(jù)庫運(yùn)維操作。等相關(guān)操作完成之后,再次打開流量開關(guān),繼續(xù)從MQ里消費(fèi)數(shù)據(jù)寫入到本地?cái)?shù)據(jù)庫內(nèi)即可。
這樣就完全避免了同時(shí)寫入數(shù)據(jù),還同時(shí)進(jìn)行數(shù)據(jù)庫運(yùn)維操作的窘境。否則在耦合的狀態(tài)下,每次進(jìn)行數(shù)據(jù)庫運(yùn)維操作,還得實(shí)時(shí)計(jì)算平臺(tái)團(tuán)隊(duì)的同學(xué)配合一起進(jìn)行各種復(fù)雜操作,才能避免線上出現(xiàn)故障。
現(xiàn)在完全不需要人家的參與了,自己團(tuán)隊(duì)就可以搞定。
加入流量開關(guān)后,架構(gòu)圖又變成了下面這樣:
6、支持多系統(tǒng)同時(shí)訂閱數(shù)據(jù)
引入了消息中間件的第三大好處:其他一些系統(tǒng)也可以按需去MQ里訂閱實(shí)時(shí)計(jì)算平臺(tái)計(jì)算好的數(shù)據(jù)。
舉個(gè)例子,這套平臺(tái)里有數(shù)據(jù)質(zhì)量監(jiān)控系統(tǒng),需要獲取計(jì)算數(shù)據(jù)進(jìn)行數(shù)據(jù)結(jié)果準(zhǔn)確性和質(zhì)量的監(jiān)控。
另外這套平臺(tái)里還有數(shù)據(jù)鏈路監(jiān)控系統(tǒng),需要將MQ里的數(shù)據(jù)作為數(shù)據(jù)計(jì)算鏈路中的一個(gè)核心點(diǎn)數(shù)據(jù)采集過來,進(jìn)行數(shù)據(jù)全鏈路的監(jiān)控和自動(dòng)追蹤。
如果沒有引入MQ消息中間件,那是不是會(huì)導(dǎo)致實(shí)時(shí)計(jì)算平臺(tái)除了將數(shù)據(jù)寫入一份到數(shù)據(jù)庫集群,還需要通過接口發(fā)送給數(shù)據(jù)質(zhì)量監(jiān)控系統(tǒng)以及數(shù)據(jù)鏈路監(jiān)控系統(tǒng)?
這樣簡(jiǎn)直坑爹到不行,N個(gè)系統(tǒng)全部耦合在一起。
但是有了消息中間件,完全可以通過MQ支持的“Pub/Sub”消息訂閱模型,不同的系統(tǒng)都可以訂閱同一份數(shù)據(jù),大家按需消費(fèi),按需處理,各個(gè)系統(tǒng)之間完全解耦。
這樣一來,整個(gè)系統(tǒng)可擴(kuò)展性瞬間提升了很多,因?yàn)楦鱾€(gè)系統(tǒng)各自迭代和演進(jìn),都不需要強(qiáng)依賴其他的系統(tǒng)了。
最后我們來看看,兩個(gè)系統(tǒng)解耦后的架構(gòu)圖: