對(duì)一個(gè)消息隊(duì)列而言儿普,高可用通常考慮的客戶端連接與服務(wù)端內(nèi)部:客戶端包含了消除單點(diǎn)故障導(dǎo)致連接失敗掷倔,保障連接與宕機(jī)后找到替代結(jié)點(diǎn)眉孩;服務(wù)端內(nèi)部包括多機(jī)房高可用與數(shù)據(jù)備份等。
以下分部分來(lái)詳細(xì)說(shuō)明:
1. 客戶端初次連接的高可用
1.1 高可用設(shè)計(jì)
用戶在使用消息中間件時(shí)勒葱,第一步要做的是創(chuàng)建與服務(wù)端的連接浪汪,為了確保這一步的高可用,我們需要避免連接服務(wù)端遇到單點(diǎn)故障的問(wèn)題凛虽。當(dāng)消息隊(duì)列集群背后某一臺(tái)機(jī)器的不可用時(shí)死遭,客戶端就無(wú)法使用整個(gè)消息隊(duì)列,這就是這個(gè)場(chǎng)景下的單點(diǎn)故障凯旋,是在高可用系統(tǒng)中不應(yīng)該出現(xiàn)的問(wèn)題呀潭。
通常來(lái)講我們可以籠統(tǒng)的把此處的HA解決方案稱為服務(wù)發(fā)現(xiàn)策略。在此類型策略的中間件系統(tǒng)中至非,有兩個(gè)必不可少的功能:
- 中間件提供一個(gè)服務(wù)發(fā)現(xiàn)層钠署,這一層的服務(wù)可以處理結(jié)點(diǎn)的注冊(cè)與探活,把各集群的結(jié)點(diǎn)管理起來(lái)荒椭。當(dāng)接到客戶端想要建立連接時(shí)谐鼎,首先訪問(wèn)服務(wù)發(fā)現(xiàn)層,接到請(qǐng)求的結(jié)點(diǎn)要使用合適的分配策略趣惠,挑出一個(gè)數(shù)據(jù)層結(jié)點(diǎn)狸棍,供這個(gè)客戶端使用,來(lái)專門(mén)來(lái)處理它后續(xù)的生產(chǎn)味悄、消費(fèi)請(qǐng)求草戈。
- 結(jié)合第一條功能,在服務(wù)發(fā)現(xiàn)層提供一個(gè)負(fù)載均衡(LB)傍菇∨魈溃客戶端在訪問(wèn)LB時(shí)曹傀,LB會(huì)將請(qǐng)求隨機(jī)轉(zhuǎn)到背后任意可用的一臺(tái)機(jī)器,同時(shí)保證LB背后的每一臺(tái)機(jī)器都可以合理的處理或轉(zhuǎn)發(fā)這個(gè)請(qǐng)求,來(lái)建立客戶端的初次連接蓬衡。
舉例來(lái)說(shuō)减宣,客戶端C發(fā)起請(qǐng)求到服務(wù)發(fā)現(xiàn)的LB后痒筒,請(qǐng)求打到了背后的機(jī)器S1上悉抵。S1根據(jù)中間件的分配策略,決定了分配S2數(shù)據(jù)結(jié)點(diǎn)給這個(gè)客戶端使用见擦《ず梗客戶端開(kāi)始與S2創(chuàng)建連接羹令,并在短期內(nèi)所有的生產(chǎn)、消費(fèi)交由S2處理损痰。這樣一來(lái)福侈,創(chuàng)建連接時(shí)的高可用的責(zé)任,就轉(zhuǎn)移到了負(fù)載均衡及消息隊(duì)列的服務(wù)注冊(cè)卢未、分配邏輯上肪凛。
服務(wù)發(fā)現(xiàn)的結(jié)點(diǎn)盡可能無(wú)狀態(tài)(每一個(gè)結(jié)點(diǎn)都可更替)且部署在多個(gè)數(shù)據(jù)中心(單機(jī)房斷電服務(wù)不停),其所依賴的下游服務(wù)也盡可能是HA的辽社,這樣一來(lái)我們?cè)诳蛻舳藙?chuàng)建連接這一步伟墙,就達(dá)到了HA。
1.2 例子
Apache Pulsar
Pulsar的元數(shù)據(jù)處理稱為Broker滴铅,任何一個(gè)接到請(qǐng)求的Broker機(jī)器戳葵,可以根據(jù)當(dāng)前處理的Topic來(lái)確認(rèn)由哪臺(tái)Broker(數(shù)據(jù)結(jié)點(diǎn))來(lái)處理,細(xì)節(jié)可見(jiàn)官方文檔汉匙。
關(guān)于LB拱烁,Pulsar提供了兩種方案,一種是自己部署噩翠,或使用Pulsar 代理)邻梆。
Apache RocketMQ
內(nèi)部有一個(gè)Name Server模塊,對(duì)數(shù)據(jù)結(jié)點(diǎn)做結(jié)點(diǎn)注冊(cè)與心跳檢測(cè)绎秒,并且負(fù)責(zé)路由請(qǐng)求。https://rocketmq.apache.org/docs/rmq-arc/
RocketMQ同時(shí)也提供了同Pulsar一樣的代理服務(wù)尼摹。
eBay NuMessage
NuMessage不區(qū)分?jǐn)?shù)據(jù)結(jié)點(diǎn)與服務(wù)發(fā)現(xiàn)結(jié)點(diǎn)见芹,當(dāng)請(qǐng)求打到NuMessage LB時(shí),請(qǐng)求會(huì)被轉(zhuǎn)發(fā)到客戶端想要的集群的主結(jié)點(diǎn)上蠢涝。主結(jié)點(diǎn)負(fù)責(zé)結(jié)點(diǎn)注冊(cè)與心跳檢測(cè)探活玄呛,以及分配結(jié)點(diǎn)給客戶端,此處的主結(jié)點(diǎn)類似于RocketMQ的Name Server和二。
Apache Kafka
同Pulsar Broker策略徘铝,但Apache Kafka需要引入額外的第三方包來(lái)做負(fù)載均衡或代理層。
2. 客戶端與服務(wù)端交互過(guò)程中的高可用
以下為eBay NuMessage為例介紹惯吕。
2.1 多數(shù)據(jù)中心高可用
當(dāng)消息隊(duì)列的數(shù)據(jù)存儲(chǔ)在多個(gè)數(shù)據(jù)中心時(shí)(Data Center惕它,下文簡(jiǎn)稱DC),發(fā)生了單個(gè)DC失效斷電废登,其它DC依然可以為客戶端提供服務(wù)淹魄,此時(shí)可以達(dá)成多DC的高可用。
NuMessage的結(jié)點(diǎn)可以部署在多個(gè)DC堡距。默認(rèn)客戶端在建立連接時(shí)甲锡,都會(huì)分配一臺(tái)對(duì)應(yīng)DC的服務(wù)端結(jié)點(diǎn)兆蕉。但如果一個(gè)DC內(nèi)的NuMessage結(jié)點(diǎn)全部宕機(jī)(或根本沒(méi)有部署)時(shí),NuMessage會(huì)為客戶端分配其它DC的服務(wù)端結(jié)點(diǎn)缤沦。這樣單DC不可用時(shí)虎韵,客戶端連到其它DC上依然可用(客戶端機(jī)器宕機(jī)與斷網(wǎng)不在考慮范圍內(nèi))。隨后當(dāng)服務(wù)端壞掉的DC重新恢復(fù)時(shí)缸废,會(huì)被服務(wù)端發(fā)現(xiàn)并嘗試重新分配同DC的結(jié)點(diǎn)給客戶端包蓝。
2.2 聚集在單數(shù)據(jù)中心的高可用
NuMessage的所有結(jié)點(diǎn)都注冊(cè)在ZooKeeper上,因此單個(gè)結(jié)點(diǎn)宕機(jī)時(shí)呆奕,同一個(gè)DC下該集群的主結(jié)點(diǎn)(后稱leader)會(huì)通過(guò)ZooKeeper了解到這件事养晋。此時(shí)客戶端再往該宕機(jī)結(jié)點(diǎn)發(fā)來(lái)請(qǐng)求必然會(huì)失敗,這類失敗在客戶端觸發(fā)了一次重新建立連接的請(qǐng)求梁钾。這一次Leader重新為這個(gè)客戶端分配機(jī)器绳泉,不會(huì)再將這個(gè)掛掉的機(jī)器納入考慮,而是分配其它健康的機(jī)器姆泻。
若NuMessage Leader結(jié)點(diǎn)宕機(jī)零酪,一樣會(huì)被其它結(jié)點(diǎn)通過(guò)ZooKeeper發(fā)現(xiàn),并觸發(fā)內(nèi)部的選主拇勃,進(jìn)而出現(xiàn)新的Leader四苇。
因此在客戶端視角,服務(wù)端連接故障時(shí)方咆,只會(huì)發(fā)生短暫的斷開(kāi)后重連月腋,以此達(dá)成了在同一DC下的高可用。
3. 服務(wù)端內(nèi)部的高可用
eBay NuMessage
的存儲(chǔ)層是Kafka瓣赂,通過(guò)默認(rèn)三個(gè)副本與rack awareness來(lái)保障一定程度的高可用榆骚。但當(dāng)數(shù)據(jù)出現(xiàn)DC斷電、磁盤(pán)問(wèn)題煌集、大規(guī)模網(wǎng)絡(luò)問(wèn)題時(shí)依然無(wú)法從存儲(chǔ)層達(dá)到HA妓肢。因此NuMessage在做了以下措施:
- 生產(chǎn)者:默認(rèn)將數(shù)據(jù)寫(xiě)入當(dāng)前DC,若失敗次數(shù)達(dá)到一定閾值或頻率苫纤,嘗試寫(xiě)入其它DC碉钠。跨DC寫(xiě)入時(shí)有更高延遲卷拘,但本DC產(chǎn)生的數(shù)據(jù)依舊能寫(xiě)入該集群喊废。
- 消費(fèi)者:有時(shí)會(huì)為Kafka部署aggregation結(jié)點(diǎn),把所有DC的數(shù)據(jù)同步到多份aggregation topic上栗弟。而消費(fèi)者只消費(fèi)其中一個(gè)aggregation topic操禀,出現(xiàn)DC斷電時(shí)切換到另一DC消費(fèi)。但消費(fèi)的offset需要映射到另一DC的對(duì)應(yīng)offset上横腿⊥切迹可參見(jiàn)uber的Kafka方案斤寂。
Uber Kafka
https://eng.uber.com/ureplicator-apache-kafka-replicator/
https://eng.uber.com/kafka/
Apache RocketMQ
結(jié)點(diǎn)分master\slave,寫(xiě)入僅寫(xiě)master揪惦,讀取時(shí)可從slave讀遍搞,因此master掛掉不影響consumer讀取。
寫(xiě)入時(shí)可寫(xiě)入多個(gè)master器腋,因此單master掛掉不影響寫(xiě)入溪猿。
Apache Kafka
Kafka將數(shù)據(jù)存于多份副本,僅有一個(gè)主副本纫塌,它可寫(xiě)可讀诊县,其它副本只能從主副本同步數(shù)據(jù)。但是在主副本宕機(jī)時(shí)措左,其它副本若數(shù)據(jù)合適可以通過(guò)選舉為新的主副本提供服務(wù)依痊。