洞察基的個(gè)人空間 http://selenalain.com/space-uid-170118.html [收藏] [復制] [RSS]

博客

粘性會(huì )話(huà)負載均衡 - MQTT Broker 集群詳解(二)

已有 576 次閱讀2022-7-26 15:28

在上一篇文章《MQTT Broker 集群詳解(一):負載均衡》中,我們簡(jiǎn)單介紹了 MQTT 負載均衡:負載均衡既可以應用于傳輸層,也可以用于應用層。在本文中,我們將詳細介紹應用層負載均衡,其中最有趣的部分:粘性會(huì )話(huà)(sticky-session)。

本文由兩部分組成,第一部分將介紹 MQTT 會(huì )話(huà),以及在分布式 MQTT Broker 集群中處理會(huì )話(huà)面臨的挑戰;第二部分是通過(guò)在 EMQX 4.3 集群前面配置 HAProxy 2.4 負載均衡器,帶讀者親自體驗如何充分利用粘性會(huì )話(huà)實(shí)現負載均衡。

MQTT 會(huì )話(huà)

為了持續接收消息,MQTT 客戶(hù)端通常會(huì )連接至 MQTT Broker 進(jìn)行訂閱并保持長(cháng)期連接。由于網(wǎng)絡(luò )問(wèn)題或客戶(hù)端軟件維護等原因,連接可能會(huì )中斷一段時(shí)間,這并不罕見(jiàn),但客戶(hù)端通常希望在重新連接成功后仍然能接收到中斷期間漏收的消息。

因此,為客戶(hù)端提供服務(wù)的 MQTT Broker 應該為客戶(hù)端保持會(huì )話(huà)(根據客戶(hù)端的請求,將「Clean-Session」標志設置為 false)。此時(shí),即使客戶(hù)端斷開(kāi)連接,訂閱者當前訂閱的主題以及傳遞給這些主題的消息(QoS1 和 2)等也會(huì )由消息服務(wù)器(broker)保留。

當具有持久會(huì )話(huà)的客戶(hù)端重新連接時(shí),它不需要重新訂閱主題,消息服務(wù)器應該將所有未發(fā)送的消息發(fā)送給該客戶(hù)端。

我們之前寫(xiě)過(guò)一篇關(guān)于 MQTT 會(huì )話(huà)的文章,如果您對 MQTT 會(huì )話(huà)的技術(shù)細節感興趣,可以通過(guò)閱讀這篇文章做進(jìn)一步了解。

會(huì )話(huà)接管

當 MQTT Brokers 形成集群時(shí),事情會(huì )變得更加復雜。從客戶(hù)端的角度來(lái)看,要連接的服務(wù)器不止一個(gè),很難知道哪個(gè)服務(wù)器最適合連接。我們需要網(wǎng)絡(luò )中的另一個(gè)關(guān)鍵組件:負載均衡器。負載均衡器成為整個(gè)集群的接入點(diǎn),并將客戶(hù)端的連接路由到集群中的某一個(gè)服務(wù)器。

如果客戶(hù)端通過(guò)負載均衡器連接到服務(wù)器(例如,node1),然后斷開(kāi)連接并稍后重新連接,則新連接可能會(huì )路由到集群中的不同服務(wù)器(例如,node3)。在這種情況下,node3 應該在客戶(hù)端斷開(kāi)連接時(shí)開(kāi)始向客戶(hù)端發(fā)送未發(fā)送的消息。

實(shí)現集群范圍的持久會(huì )話(huà)有很多不同的策略。例如,整個(gè)集群可以共享一個(gè)全局存儲來(lái)保存客戶(hù)端的會(huì )話(huà)。

然而,更具可擴展性的解決方案通常以分布式方式解決這個(gè)問(wèn)題,即數據從一個(gè)節點(diǎn)遷移到另一個(gè)節點(diǎn)。這種遷移稱(chēng)為會(huì )話(huà)接管。會(huì )話(huà)接管應該對客戶(hù)端完全透明,但它是有代價(jià)的,尤其是當有很多消息需要處理時(shí)。

會(huì )話(huà)接管

粘性會(huì )話(huà)解決方案

這里的「粘性」一詞指的是負載均衡器能夠在重新連接時(shí)將客戶(hù)端路由到之前服務(wù)器的能力,這可以避免會(huì )話(huà)接管。當有許多客戶(hù)端在同一時(shí)間重新連接時(shí),或者在一個(gè)有問(wèn)題的客戶(hù)端反復斷開(kāi)連接并再次連接的情況下,這是一個(gè)特別有用的功能。

為了讓負載均衡器以「粘性」方式分派連接,服務(wù)器需要知道連接請求中的客戶(hù)端標識符(有時(shí)是用戶(hù)名)——這需要負載均衡器檢查 MQTT 數據包以查找此類(lèi)信息。

一旦獲得客戶(hù)端標識符(或用戶(hù)名),對于靜態(tài)集群,服務(wù)器可以將客戶(hù)端標識符(或用戶(hù)名)散列到服務(wù)器 ID;蛘邽榱烁玫撵`活性,負載均衡器可以選擇維護一個(gè)從客戶(hù)端標識符(或用戶(hù)名)到目標節點(diǎn) ID 的映射表。

在下一節中,我們將演示 HAProxy 2.4 中的粘性表策略。

使用 HAProxy 2.4 實(shí)現粘性會(huì )話(huà)

為了盡量減少先決條件,在這個(gè)演示集群中,我們將在 docker 容器中啟動(dòng)兩個(gè) EMQX 節點(diǎn)和一個(gè) HAProxy 2.4。

創(chuàng )建 docker 網(wǎng)絡(luò )

為了使容器彼此連接,我們?yōu)樗鼈儎?chuàng )建了一個(gè) docker 網(wǎng)絡(luò )。

docker network create test.net
啟動(dòng)兩個(gè) EMQX 4.3 節點(diǎn)

為了使節點(diǎn)彼此連接,應該在網(wǎng)絡(luò )名稱(chēng)空間(test.net)中分配容器名稱(chēng)和 EMQX 節點(diǎn)名稱(chēng)。

啟動(dòng) node1
docker run -d \ --name n1.test.net \ --net test.net \ -e EMQX_NODE_NAME=emqx@n1.test.net \ -e EMQX_LISTENER__TCP__EXTERNAL__PROXY_PROTOCOL=on \ emqx/emqx:4.3.7
啟動(dòng) node2
docker run -d \ --name n2.test.net \ --net test.net \ -e EMQX_NODE_NAME=emqx@n2.test.net \ -e EMQX_LISTENER__TCP__EXTERNAL__PROXY_PROTOCOL=on \ emqx/emqx:4.3.7

注意環(huán)境變量

EMQX_LISTENER__TCP__EXTERNAL__PROXY_PROTOCOL. 該變量是為T(mén)CP監聽(tīng)器啟用二進(jìn)制代理協(xié)議,以便服務(wù)器可以獲得客戶(hù)端的真實(shí) IP 地址信息,而不是負載均衡器的 IP 地址。

使 EMQX 節點(diǎn)加入集群
docker exec -it n2.test.net emqx_ctl cluster join emqx@n1.test.net

如果一切按預期進(jìn)行,應該打印輸出這樣的日志:

[EMQX] emqx shutdown for join Join the cluster successfully. Cluster status: #{running_nodes => ['emqx@n1.test.net','emqx@n2.test.net'], stopped_nodes => []} <div class="copy-btn" data-clipboard-text="[EMQX] emqx shutdown for join Join the cluster successfully. Cluster status: #{running_nodes => ['emqx@n1.test.net','emqx@n2.test.net'], stopped_nodes => []} " style="box-sizing: inherit; cursor: pointer; position: absolute; top: 20px; right: 0px; width: 60px; height: 20px; font-size: 14px; line-height: 20px; text-align: center; color: rgb(134, 109, 255); background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAclBMVEUAAAAjIyMfHx8gICAeHh4jIyMfHx8eHh4eHh4eHh4dHR0fHx8eHh4eHh4eHh4dHR0dHR0eHh4dHR0eHh4eHh4eHh4dHR0eHh4eHh4eHh4eHh4eHh4eHh4dHR0eHh4dHR0dHR0eHh4eHh4eHh4dHR0dHR1LlvbwAAAAJXRSTlMAFhkgIiQpKzs8PUJFXXd6e4eMkJmprrK9w8Td3+Hm6/X4+fr9WCdMmgAAAMZJREFUOMvt1MkOgzAMBNCwUyi0hLWsATL//4s9VSKOpXKsUOc4etjJIQhx1UT1CDNzmzAuW2FHPywXKEiPdG6+aWtmiYpZk6OlVY+YgS5mc2/Z75iGQ7rCEUIIARj3UMw9lrsFoxVV7If+MWmDxaGwhmSO16CgcITHwBQdheaBP/Ex/OHvQg/jOShRn4BTXGGNvsIQAFQmTkzc+zIwqhkuA2940apFzsAKJa0SveV0piehAuvjp2Ze4Zoxa5J2Jmyso8v+jd85fiT1dzutbAAAAABJRU5ErkJggg==") 50% center / 20px 20px no-repeat rgb(246, 248, 250);">
啟動(dòng) HAProxy 2.4

創(chuàng )建文件 /tmp/haproxy.config,內容如下:

global   log stdout format raw daemon debug   nbproc 1   nbthread 2   cpu-map auto:1/1-2 0-1   # Enable the HAProxy Runtime API   # e.g. echo "show table emqx_tcp_back" | sudo socat stdio tcp4-connect:172.100.239.4:9999   stats socket :9999 level admin expose-fd listeners defaults   log global   mode tcp   option tcplog   maxconn 1024000   timeout connect 30000   timeout client 600s   timeout server 600s frontend emqx_tcp   mode tcp   option tcplog   bind *:1883   default_backend emqx_tcp_back backend emqx_tcp_back   mode tcp   # Create a stick table for session persistence   stick-table type string len 32 size 100k expire 30m   # Use ClientID / client_identifier as persistence key   stick on req.payload(0,0),mqtt_field_value(connect,client_identifier)   # send proxy-protocol v2 headers   server emqx1 n1.test.net:1883 check-send-proxy send-proxy-v2   server emqx2 n2.test.net:1883 check-send-proxy send-proxy-v2

在測試 docker 網(wǎng)絡(luò )中啟動(dòng) haproxy:

docker run -d \   --net test.net \   --name proxy.test.net \   -p 9999:9999 \   -v /tmp/haproxy.cfg:/haproxy.cfg \   haproxy:2.4 haproxy -f /haproxy.cfg
測試

現在我們使用流行的 mosquitto MQTT 客戶(hù)端(也在 docker 中)對其進(jìn)行測試。

我們啟動(dòng)一個(gè)訂閱者(名為 subscriber1)訂閱 t/# 主題

docker run --rm -it --net test.net eclipse-mosquitto \ mosquitto_sub -h proxy.test.net -t 't/#' -I subscriber1

然后從另一個(gè)客戶(hù)端向 t/xyz 發(fā)布一條 hello 消息

docker run --rm -it --net test.net eclipse-mosquitto \ mosquitto_pub -h proxy.test.net -t 't/xyz' -m 'hello'

如果一切都按預期進(jìn)行,訂閱者應該打印出 hello 消息。

檢查 HAProxy 中的粘性表

我們還可以使用如下命令檢查在 HAProxy 中創(chuàng )建的粘性表。這需要 socat 命令,所以我們從 docker 主機運行它。

show table emqx_tcp_back" | sudo socat stdio tcp4-connect:127.0.0.1:9999

該命令應該打印當前連接,如下所示:

# table: emqx_external_tcp_listners, type: string, size:102400, used:1 0x7f930c033d90: key=subscriber1 use=0 exp=1793903 server_id=2 server_key=emqx2

在這個(gè)例子中,客戶(hù)端 subscriber1 被固定連接到服務(wù)器 emqx2。

結語(yǔ)

至此,我們可以了解到從客戶(hù)端的角度看,EMQX 集群是如何通過(guò)負載均衡器對外部提供服務(wù)的。

在本系列文章的后續內容中,我們將跟蹤一個(gè) MQTT 消息從發(fā)布者到訂閱者的全過(guò)程,以便大家了解 EMQX 如何將它在集群中復制和轉發(fā)。敬請期待。

本系列中的其它文章
關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
返回頂部
午夜高清国产拍精品福利|亚洲色精品88色婷婷七月丁香|91久久精品无码一区|99久久国语露脸精品|动漫卡通亚洲综合专区48页