EMQ 是一款基于高并發(fā)的 Erlang/OTP 語言平臺設(shè)計,支持百萬級連接和分布式集群,發(fā)布/訂閱模式的開源MQTT消息服務(wù)器。

EMQ 單節(jié)點(diǎn)支持100萬并發(fā)MQTT連接峰值負(fù)載,超過了絕大多數(shù)的后端服務(wù)對消息的處理能力。因此往往需要多個后端服務(wù)節(jié)點(diǎn)來分擔(dān)。但是基于的 MQTT 3.1.1 協(xié)議標(biāo)準(zhǔn),如果多個后端服務(wù)節(jié)點(diǎn)訂閱了相同的 topic,來自這些 topic 消息會被同時派發(fā)給所有的后端服務(wù)。為了解決這樣的問題,EMQ 提供了共享訂閱這個機(jī)制。
共享訂閱 (Shared Subscription) 是指在多訂閱者間采用分組負(fù)載平衡方式派發(fā)消息
EMQ 提供了如下兩種共享訂閱的方式:
- $queue/ 隊列共享訂閱
- $share/<group/ 分組共享訂閱
隊列共享訂閱是指以 $queue/ 開頭的 topic 例如 $queue/topic1,如果有多個客戶端同時訂閱了,EMQ 會把發(fā)送到 topic1 的消息以負(fù)載均衡的方式派發(fā)給所有客戶端,保證一條消息只會派發(fā)給一個客戶端。需要注意前綴 $queue 只適用于訂閱時,發(fā)布消息時不需要。
分組共享訂閱是一個更加靈活的方式,實現(xiàn)方式為所有以 $share/<group>/ 開頭的的 topic 會以 group 來分組進(jìn)行消息的負(fù)載均衡派發(fā)。例如有4個客戶端依次訂閱了$share/group1/topic1,$share/group1/topic1,$share/group2/topic1 和 $share/group1/topic1。所有發(fā)送到 topic1 的消息會被同時派發(fā)到分組 group1 和 group2,但是兩個分組中的每次都只會有一個客戶端收到消息。同樣前綴$share/<group>/ 只適用于訂閱時,發(fā)布消息時不需要。
以上都是基于單個 EMQ 節(jié)點(diǎn)的共享訂閱方法,在多個 EMQ 節(jié)點(diǎn)組成的集群環(huán)境下也能實現(xiàn)共享訂閱的消息只會到達(dá)一個或者每組中的一個訂閱客戶端嗎?
很遺憾,答案是不能。雖然 EMQ 能簡單的通過 HAProxy 來搭建分布式集群,但是直到最新的 2.3.11 版本,都沒有支持集群環(huán)境下的共享訂閱。如果在集群中使用共享訂閱,在消息到達(dá)時,集群機(jī)制會把消息發(fā)送到每個 EMQ 節(jié)點(diǎn)上,隨后每個 EMQ 節(jié)點(diǎn)會把消息以負(fù)載均衡的方式派發(fā)給與自己建立連接的訂閱客戶端。換句話說,集群環(huán)境中的每個節(jié)點(diǎn)上都會有一個或者每組一個訂閱客戶端收到共享訂閱的消息。
幸運(yùn)的是,結(jié)合 EMQ 提供的本地訂閱機(jī)制可以實現(xiàn),可實現(xiàn)偽集群下的共享訂閱。
本地訂閱(Local Subscription) 只在本節(jié)點(diǎn)創(chuàng)建訂閱與路由表,不會在集群節(jié)點(diǎn)間廣播全局路由
本地訂閱的方式跟隊列共享訂閱很相似,都是在普通的 topic 前加上固定的前綴。本地共享訂閱的前綴是 $local/。
使用本地共享訂閱以后,來自訂閱的 topic 的消息只會在消息發(fā)布客戶端連接的 EMQ 節(jié)點(diǎn)上進(jìn)行派發(fā),也就做到了只有這個節(jié)點(diǎn)上一個或者每組中的一個共享訂閱客戶端收到消息。
如果消息發(fā)布客戶端所在的 EMQ 節(jié)點(diǎn)上沒有訂閱客戶端,由于本地訂閱的特性,其他節(jié)點(diǎn)上訂閱客戶端也無法收到消息。因此必須保證 EMQ 集群中的每個節(jié)點(diǎn)上都至少得一個本地共享訂閱客戶端才能達(dá)真正意義上的共享訂閱。
由于該實現(xiàn)機(jī)制要求每個 EMQ 節(jié)點(diǎn)上都有共享訂閱客戶端,結(jié)合業(yè)務(wù)就是要求每個 EMQ 節(jié)點(diǎn)上至少有一個消息處理服務(wù)連接,考慮備份則每個節(jié)點(diǎn)需要至少兩個服務(wù)。擴(kuò)容 EMQ 節(jié)點(diǎn)需要同時對服務(wù)節(jié)點(diǎn)相應(yīng)擴(kuò)容,因而稱該實現(xiàn)方式為偽集群環(huán)境下的共享訂閱。
EMQ 官方團(tuán)隊已經(jīng)表明會在下次大版本更新時支持集群下的共享訂閱,因此如果目前單 EMQ 節(jié)點(diǎn)足夠支撐業(yè)務(wù)需求可延緩集群化時間,等待下個大版本更新的發(fā)布。