在上一篇文章《MQTT Broker 集群詳解(一):負(fù)載均衡》中,我們簡(jiǎn)單介紹了 MQTT 負(fù)載均衡:負(fù)載均衡既可以應(yīng)用于傳輸層,也可以用于應(yīng)用層。在本文中,我們將詳細(xì)介紹應(yīng)用層負(fù)載均衡,其中最有趣的部分:粘性會(huì)話(sticky-session)。
本文由兩部分組成,第一部分將介紹 MQTT 會(huì)話,以及在分布式 MQTT Broker 集群中處理會(huì)話面臨的挑戰(zhàn);第二部分是通過在 EMQX 4.3 集群前面配置 HAProxy 2.4 負(fù)載均衡器,帶讀者親自體驗(yàn)如何充分利用粘性會(huì)話實(shí)現(xiàn)負(fù)載均衡。
MQTT 會(huì)話為了持續(xù)接收消息,MQTT 客戶端通常會(huì)連接至 MQTT Broker 進(jìn)行訂閱并保持長(zhǎng)期連接。由于網(wǎng)絡(luò)問題或客戶端軟件維護(hù)等原因,連接可能會(huì)中斷一段時(shí)間,這并不罕見,但客戶端通常希望在重新連接成功后仍然能接收到中斷期間漏收的消息。
因此,為客戶端提供服務(wù)的 MQTT Broker 應(yīng)該為客戶端保持會(huì)話(根據(jù)客戶端的請(qǐng)求,將「Clean-Session」標(biāo)志設(shè)置為 false)。此時(shí),即使客戶端斷開連接,訂閱者當(dāng)前訂閱的主題以及傳遞給這些主題的消息(QoS1 和 2)等也會(huì)由消息服務(wù)器(broker)保留。
當(dāng)具有持久會(huì)話的客戶端重新連接時(shí),它不需要重新訂閱主題,消息服務(wù)器應(yīng)該將所有未發(fā)送的消息發(fā)送給該客戶端。
我們之前寫過一篇關(guān)于 MQTT 會(huì)話的文章,如果您對(duì) MQTT 會(huì)話的技術(shù)細(xì)節(jié)感興趣,可以通過閱讀這篇文章做進(jìn)一步了解。
會(huì)話接管當(dāng) MQTT Brokers 形成集群時(shí),事情會(huì)變得更加復(fù)雜。從客戶端的角度來看,要連接的服務(wù)器不止一個(gè),很難知道哪個(gè)服務(wù)器最適合連接。我們需要網(wǎng)絡(luò)中的另一個(gè)關(guān)鍵組件:負(fù)載均衡器。負(fù)載均衡器成為整個(gè)集群的接入點(diǎn),并將客戶端的連接路由到集群中的某一個(gè)服務(wù)器。
如果客戶端通過負(fù)載均衡器連接到服務(wù)器(例如,node1),然后斷開連接并稍后重新連接,則新連接可能會(huì)路由到集群中的不同服務(wù)器(例如,node3)。在這種情況下,node3 應(yīng)該在客戶端斷開連接時(shí)開始向客戶端發(fā)送未發(fā)送的消息。
實(shí)現(xiàn)集群范圍的持久會(huì)話有很多不同的策略。例如,整個(gè)集群可以共享一個(gè)全局存儲(chǔ)來保存客戶端的會(huì)話。
然而,更具可擴(kuò)展性的解決方案通常以分布式方式解決這個(gè)問題,即數(shù)據(jù)從一個(gè)節(jié)點(diǎn)遷移到另一個(gè)節(jié)點(diǎn)。這種遷移稱為會(huì)話接管。會(huì)話接管應(yīng)該對(duì)客戶端完全透明,但它是有代價(jià)的,尤其是當(dāng)有很多消息需要處理時(shí)。
這里的「粘性」一詞指的是負(fù)載均衡器能夠在重新連接時(shí)將客戶端路由到之前服務(wù)器的能力,這可以避免會(huì)話接管。當(dāng)有許多客戶端在同一時(shí)間重新連接時(shí),或者在一個(gè)有問題的客戶端反復(fù)斷開連接并再次連接的情況下,這是一個(gè)特別有用的功能。
為了讓負(fù)載均衡器以「粘性」方式分派連接,服務(wù)器需要知道連接請(qǐng)求中的客戶端標(biāo)識(shí)符(有時(shí)是用戶名)——這需要負(fù)載均衡器檢查 MQTT 數(shù)據(jù)包以查找此類信息。
一旦獲得客戶端標(biāo)識(shí)符(或用戶名),對(duì)于靜態(tài)集群,服務(wù)器可以將客戶端標(biāo)識(shí)符(或用戶名)散列到服務(wù)器 ID。或者為了更好的靈活性,負(fù)載均衡器可以選擇維護(hù)一個(gè)從客戶端標(biāo)識(shí)符(或用戶名)到目標(biāo)節(jié)點(diǎn) ID 的映射表。
在下一節(jié)中,我們將演示 HAProxy 2.4 中的粘性表策略。
使用 HAProxy 2.4 實(shí)現(xiàn)粘性會(huì)話為了盡量減少先決條件,在這個(gè)演示集群中,我們將在 docker 容器中啟動(dòng)兩個(gè) EMQX 節(jié)點(diǎn)和一個(gè) HAProxy 2.4。
創(chuàng)建 docker 網(wǎng)絡(luò)為了使容器彼此連接,我們?yōu)樗鼈儎?chuàng)建了一個(gè) docker 網(wǎng)絡(luò)。
為了使節(jié)點(diǎn)彼此連接,應(yīng)該在網(wǎng)絡(luò)名稱空間(test.net)中分配容器名稱和 EMQX 節(jié)點(diǎn)名稱。
啟動(dòng) node1使 EMQX 節(jié)點(diǎn)加入集群注意環(huán)境變量
EMQX_LISTENER__TCP__EXTERNAL__PROXY_PROTOCOL. 該變量是為TCP監(jiān)聽器啟用二進(jìn)制代理協(xié)議,以便服務(wù)器可以獲得客戶端的真實(shí) IP 地址信息,而不是負(fù)載均衡器的 IP 地址。
如果一切按預(yù)期進(jìn)行,應(yīng)該打印輸出這樣的日志:
創(chuàng)建文件 /tmp/haproxy.config,內(nèi)容如下:
在測(cè)試 docker 網(wǎng)絡(luò)中啟動(dòng) haproxy:
現(xiàn)在我們使用流行的 mosquitto MQTT 客戶端(也在 docker 中)對(duì)其進(jìn)行測(cè)試。
我們啟動(dòng)一個(gè)訂閱者(名為 subscriber1)訂閱 t/# 主題
然后從另一個(gè)客戶端向 t/xyz 發(fā)布一條 hello 消息
如果一切都按預(yù)期進(jìn)行,訂閱者應(yīng)該打印出 hello 消息。
檢查 HAProxy 中的粘性表我們還可以使用如下命令檢查在 HAProxy 中創(chuàng)建的粘性表。這需要 socat 命令,所以我們從 docker 主機(jī)運(yùn)行它。
該命令應(yīng)該打印當(dāng)前連接,如下所示:
在這個(gè)例子中,客戶端 subscriber1 被固定連接到服務(wù)器 emqx2。
結(jié)語至此,我們可以了解到從客戶端的角度看,EMQX 集群是如何通過負(fù)載均衡器對(duì)外部提供服務(wù)的。
在本系列文章的后續(xù)內(nèi)容中,我們將跟蹤一個(gè) MQTT 消息從發(fā)布者到訂閱者的全過程,以便大家了解 EMQX 如何將它在集群中復(fù)制和轉(zhuǎn)發(fā)。敬請(qǐng)期待。
本系列中的其它文章