MQTT Broker 選型

broker的主要職責是接受發布者發布的所有消息,并將其過濾后分發給不同的消息訂閱者。
如今有很多的broker,下面就是一張關于各種broker對比的圖片:

image

目前我用過的有mosquitto和emqttd(2.0版本后改叫EMQ),因為目前的需求是希望做每秒10萬以上的數據接入,所以需要考慮建立集群。但是在使用mosquitto的過程中發現他不支持集群,所以就放棄了,轉投emqttd。
在使用mosquitto過程中發現了一些問題:
在使用mosquitto時,如果想使用集群的話,可能會需要進行二次開發。目前只支持橋接。并且他在遍歷時的效率非常低,使得他無法支持大量的客戶端或者操作過于頻繁的操作(比如十萬或百萬級別的客戶端同時發送數據)
emqttd有以下優點:

  • 可靠傳輸。MQTT可以保證消息可靠安全的傳輸,并可以與企業應用簡易集成。
  • 消息推送。支持消息實時通知、豐富的推送內容、靈活的Pub-Sub以及消息存儲和過濾。
  • 低帶寬、低耗能、低成本。占用移動應用程序帶寬小,并且帶寬利用率高,耗電量較少。
  • 是中國人寫的一個開源的項目,所以使用起來學習成本比較低,容易上手。

EMQ 2.0 (Erlang/Enterprise/Elastic MQTT Broker) 是基于 Erlang/OTP 語言平臺開發,支持大規模連接和分布式集群,發布訂閱模式的開源 MQTT 消息服務器。(抄自 EMQ官方文檔)


一、MQTT Broker的需求

1、基本需求

1)支持 mqtt3.1 / mqtt3.1.1協議(可選 mqtt5.0)

3.1和3.1.1是最常見的協議版本,幾乎目前生產的IoT設備都支持,所以Broker也必須支持。至于5.0版本,目前各大Broker都在努力支持,不過還需要一些時間才會普及。

2)支持QoS0、QoS1(可選QoS2)

各大廠商都至少支持了QoS1,保證消息到達。一般的場景下不會用到QoS2,所以可以選擇性地考慮支持QoS2

3)支持遺囑消息

這是必須支持的功能,通常設備斷開都不是主動斷開的,而是沒有電了才斷開,屬于異常斷開,需要設置遺囑消息來通知后端服務或者其他設備進行后續處理。

4)支持持久化

一些數據如QoS1消息、持久Session,需要支持持久化,這是MQTT協議規定的。

5)支持多種連接方式

MQTT over TCP:最基礎的連接方式

MQTT over Websocket:在Websocket之上做MQTT封裝,對APP這種客戶端來說很友好

MQTT over TCP/SSL:基礎連接方式做通信加密,通常SSL采用TLS

MQTT over Websocket/SSL:Websocket做通信加密,通常SSL采用TLS

6)(可選 保留消息)

保留消息的利用場景幾乎可以忽略,而帶來的查詢成本會很高(每次訂閱主題都要查一遍有沒有保留消息,再加上通配符匹配,時延很高),所以不一定需要支持,具體應用具體分析。

7)支持集群

Broker要支持保持海量MQTT連接,需要做集群。集群的難點在于Session的持久化和集群通信。我們既要持久化Session的各項數據,例如正在發送但未收到ACK的QoS1消息,又要保證提取速度,這就是矛盾的事情。而根據訂閱信息在內存中構建的訂閱樹,需要整個集群同步,如何做集群同步也是一個難點。任何一個簡單的功能,像發現相同ClientID則踢掉舊會話,一旦做到集群里,就是不容易處理的事情。

8)支持自定義驗證方式

驗證客戶端的合法性有三點:CONNECT階段驗證是否允許連接、PUBLISH階段驗證是否允許發布、SUBSCRIBE階段驗證是否允許訂閱。

CONNECT階段需要驗證ClientID、Username、Password、IP四項,不過大部分開源Broker都只支持Username和Password的驗證。

PUBLISH、SUBSCRIBE的驗證的目的是防止非法客戶端訂閱別人的主題,向別人的主題發布消息。但每臺設備每次訂閱、發布都要驗證一次頻率巨高,所以需要設計Cache和高效查詢機制。

2、高級功能:支持共享訂閱

共享訂閱的具體含義是,多個客戶端訂閱同一個主題,消息只會被分發給其中的一個客戶端。

共享訂閱主要針對的是需要客戶端負載均衡的場景,比如后端服務多個Worker,需要共享訂閱來只讓一個Worker得到數據。但仔細地想一想,后端服務一定有大量消息扇入,在Broker端用共享訂閱可能會導致內存爆炸,還不如直接發到Kafka,利用Kafka的負載均衡來做。不過現在的Broker都在逐漸支持共享訂閱,所以也是一個趨勢吧。

二、MQTT Broker官方資料

官方相關鏈接:

mqtt官方整理的開源Broker簡要列表

mqtt官方整理的開源Broker詳細介紹

mqtt官方整理的開源Broker特性和性能對比

三、體驗過的MQTT Broker及其對比

我以為物聯網已經很成熟了,事實上最近才有大量產品上線,網上可以參考的內容不多。體驗了很多開源Broker,開源的Broker根本不能直接上生產環境,只有商業版的HiveMQ和商業版的EMQ才滿足了所有的需求。先列個表,這些已經算是比較優秀的Broker了,分析主要特性:

  • ? - 支持

  • ? - 不支持

  • ? - 不了解

  • § - 支持但做得不好(有限制)

圖片.png

1、mosquitto

【簡介】

image

mosquitto是ecplise出的開源Broker,由C/C++語言編寫,目前最新版v1.5.8,是一個開源MQTT Broker。

【官方文檔宣稱的特性】

協議:支持mqtt 3.1 / mqtt 3.1.1

【實際的使用限制分析】

“趁著年輕”大佬早在2013年就開始研究了,當時的版本是1.2.2,那時候還有一些基礎的性能問題,比如用的poll而沒有用epoll,內存方面沒有優化,多線程主要靠加鎖等等,預計可支持10W左右鏈接。于是大佬自己修改了一個版本kulv2012/mosquitto,優化了那些性能,這已經是五年前了……

同樣的,“逍遙子”2015年在CSDN上分析了mosquitto1.2的源碼,指出epoll需要優化、訂閱樹需要優化。將訂閱樹改為了HASH表,直接查找,限制了通配符訂閱功能但速度提升明顯。

mosquitto可以通過橋接的方式進行集群,橋接就是靠一個mosquitto實例去做轉發,其他的broker可以轉發給它而已,如果客戶端切換節點,session就會消失,并且一旦中轉Broker掛掉,整個集群就掛了,這是一種偽集群。“hui6075”在mosquitto上做了真集群hui6075/mosquitto-cluster,也就是自定義一些消息,session可以通過這些消息進行轉移。

最新版本早就沒有了那些性能問題,也早就從poll改為epoll了(忘了在哪兒看到的),目前正在努力支持mqtt5,出了一個MQTT5測試版,暫時還不支持共享訂閱。

無論如何,總結一句話,mosquitto是為了嵌入式設備而生,正如官方的介紹,mosquitto足夠輕量,可以運行在任何低功率單片機上,包括嵌入式傳感器、手機設備、嵌入式微處理器,mosquitto用C語言編寫、集群做的如此簡單就是證明,它不適合用來做云服務的MQTT Broker。

【推薦延伸閱讀】

mosquitto github開源代碼

mosquitto 官方網站

趁著年輕:《Mosquitto pub/sub服務實現代碼淺析-主體框架》

小諾Z《Mosquitto集群搭建》

逍遙子《mosquitto源碼分析(一)》簡介

逍遙子《mosquitto源碼分析(二)》數據結構

逍遙子《mosquitto源碼分析(三)》訂閱樹

逍遙子《mosquitto源碼分析(四)》訂閱樹

逍遙子《mosquitto源碼分析(五)》Poll和消息收發

逍遙子《mosquitto源碼分析(六)》日志

逍遙子《Mosquito的優化——epoll優化(七)》

逍遙子《Mosquito的優化——訂閱樹優化(八)》

逍遙子《Mosquito的優化——其他優化(九)》

2、EMQ (emqttd)

【簡介】

image

EMQ是國人出產的一個開源Broker,已經用于很多企業生產了,幾乎是目前的全能Broker了,文檔和資料也非常齊全,但它是用Erlang語言編寫的,這是一個不常見的語言。有兩個版本2.0和3.0,最大的區別是3.0的集群化更好,支持集群共享訂閱功能,2.0只支持本地共享訂閱功能。同時3.0支持mqtt5.0,其他的都是一些性能優化。

【官方文檔宣稱的特性】

MQTT 3.1 / 3.1.1 / 5.0(EMQ3.0)

完整QoS支持

單節點100萬連接

分布式集群或橋接(還支持mosquitto橋接、rsmb橋接)、腦裂自動愈合

LDAP, MySQL, PostgreSQL, Redis, MongoDB等驗證插件

完整連接方式支持

API、Web監控界面

本地共享訂閱(EMQ2.0)、集群共享訂閱(EMQ3.0)

$SYS統計信息主題

自定義插件開發

【實際的使用限制分析】

幾乎是完美的,只有一點限制,那就是開源版本不支持消息持久化:

EMQ 1.0 版本不支持服務器內部消息持久化,這是一個架構設計選擇。首先,EMQ 解決的核心問題是連接與路由;其次,我們認為內置持久化是個錯誤設計。
傳統內置消息持久化的 MQ 服務器,比如廣泛使用的 JMS 服務器 ActiveMQ,幾乎每個大版本都在重新設計持久化部分。內置消息持久化在設計上有兩個問題:
1)如何平衡內存與磁盤使用?消息路由基于內存,消息存儲是基于磁盤。
2)多服務器分布集群架構下,如何放置 Queue 如何復制 Queue 的消息?
Kafka 在上述問題上,做出了正確的設計:一個完全基于磁盤分布式 Commit Log 的消息服務器。
EMQ 2.0 版本將發布 EMQ X 平臺產品,支持消息持久化到 Redis、Kafka、Cassandra、PostgreSQL 等數據庫。
設計上分離消息路由與消息存儲職責后,數據復制容災備份甚至應用集成,可以在數據層面靈活實現。

這是MQTT的標準協議規定的啊,看完源碼后發現它的普通Publish消息是持久化到分布式數據庫Mnesia了(但是如果節點崩得多也會丟失),而離線消息隊列是基于內存的,也就是Broker一崩消息就丟失了,很多人都在尋求解決方法,都沒有好的方法。還有個問題是后端服務怎么接上去,EMQ的設計根本沒提到后端服務的問題。大部分的解決方法都是編寫一個插件,把MQTT消息丟到Kafka,后端服務處理Kafka的數據,但是后端服務除了收還要發呀,如果直接作為客戶端連上去,Broker會內存爆炸因為后端服務要發送的消息太多了。如果你有好的想法,請一定要教教我。

【推薦延伸閱讀】

EMQ github 源碼

EMQ wiki

EMQ 官網

知乎:分布式開源物聯網MQTT消息服務器EMQ怎么做數據的存儲?

Dr_C《EMQ集成Kafka插件編寫過程 emq_plugin_kafka》

響亮響亮《EMQ擴展插件-emq_plugin_kafka》

無腦仔的小明《物聯網架構成長之路(3)-EMQ消息服務器了解》

無腦仔的小明《物聯網架構成長之路(4)-EMQ插件創建》

無腦仔的小明《物聯網架構成長之路(5)-EMQ插件配置》

無腦仔的小明《物聯網架構成長之路(6)-EMQ權限控制》

無腦仔的小明《物聯網架構成長之路(7)-EMQ權限驗證小結》

無腦仔的小明《物聯網架構成長之路(8)-EMQ-Hook了解、連接Kafka發送消息》

無腦仔的小明《物聯網架構成長之路(12)-物聯網架構小結1》

3、HiveMQ

【簡介】

image

HiveMQ是企業級的Broker,用Java編寫,代碼真的賞心悅目。由于是收費的,沒有公開的源碼可以看,我只從一個反編譯的大佬那里看到幾張截圖而已,只是一些截圖就能夠看到編寫者的Java水平真的很高……

【官方文檔宣稱的特性】

MQTT 3.1 / 3.1.1 / 5.0

完整QoS支持

分布式集群支持

持久化支持

流量控制支持

完整連接方式支持

IPv6支持

集群共享訂閱

$SYS統計信息主題

JMX性能監控

日志打印

Docker部署

……

【實際的使用限制分析】

功能上齊全得讓人想哭,唯一的限制就是收費,沒有任何源碼可以參考。它的集群是基于Jgroups的,持久化的數據都是本地+Jgroups同步,自己編寫了一套一致性Hash和VectorClock解決沖突……訂閱樹也是完整的訂閱樹,優秀的緩存和并發訪問控制,集群進行數據同步。多線程和并發等用的google的guava進行防御性編程,實在是太厲害了。如果你有源碼,請多發給我一份,我只是用來學習,謝謝!

【推薦延伸閱讀】

HiveMQ官網

西安PP《MQTT---HiveMQ源碼詳解(一)概覽》

西安PP《MQTT---HiveMQ源碼詳解(二)結構與啟動》

西安PP《MQTT---HiveMQ源碼詳解(三)配置加載》

西安PP《MQTT---HiveMQ源碼詳解(四)插件加載》

西安PP《MQTT---HiveMQ源碼詳解(五)Netty-啟動與Listeners加載》

西安PP《MQTT---HiveMQ源碼詳解(六)Netty-Handlers總覽》

西安PP《MQTT---HiveMQ源碼詳解(七)Netty-SSL/NoSSL》

西安PP《MQTT---HiveMQ源碼詳解(八)Netty-WebSocket》

西安PP《MQTT---HiveMQ源碼詳解(九)Netty-Codec》

西安PP《MQTT---HiveMQ源碼詳解(十)Netty-Statistics》

西安PP《MQTT---HiveMQ源碼詳解(十一)Netty-Throttling》

西安PP《MQTT---HiveMQ源碼詳解(十二)Netty-MQTT消息、事件處理(流程)》

西安PP《MQTT---HiveMQ源碼詳解(十三)Netty-MQTT消息、事件處理(源碼舉例解讀)》

西安PP《MQTT---HiveMQ源碼詳解(十四)Persistence-LocalPersistence》

西安PP《MQTT---HiveMQ源碼詳解(十五)Persistence-Cluster/Single》

西安PP《MQTT---HiveMQ源碼詳解(十六)TopicTree》

西安PP《MQTT---HiveMQ源碼詳解(十七)Cluster-Consistent Hashing Ring & Node Lifecycle》

西安PP《MQTT---HiveMQ源碼詳解(十八)Cluster-kryo與Serializer》

西安PP《MQTT---HiveMQ源碼詳解(十九)Cluster-Request/Response》

西安PP《MQTT---HiveMQ源碼詳解(二十)Cluster-Replicate/VectorClock》

西安PP《MQTT---HiveMQ源碼詳解(二十一)完結篇》

西安PP《MQTT---HiveMQ源碼詳解(外傳)為什么使用Xodus》

4、MqttWk

【簡介】

一個阿里大佬編寫的基于 nutzboot + netty + redis + kafka 實現的MQTT服務開源broker,代碼非常簡潔干凈,一看就懂。nutzboot是國人編寫的類似于springboot的開源架構,它有一系列的產品,功能和代碼外觀都和spring全家桶很像,但比spring全家桶輕量。

【官方文檔宣稱的特性】

MQTT 3.1.1

完整的QoS服務

完整的連接方式

Kafka消息轉發

集群功能

分發重試

【實際的使用限制分析】

1)MessageQueue沒有排序:是直接插入Redis的key-value,并不是一個隊列

2)消息分發重試很差:對于未確認的QoS1消息,只會在重新連接的時候下發,如果一直在線就會一直淤積

3)集群功能很差:用Redis的訂閱發布當作消息總線來構建集群,而且我剛熟悉的時候還有問題(1.0.7版本),提交了issue后更新到1.0.8,不過集群這塊還是不太好。

4)Kafka消息轉發:只是單純地轉發而已,沒有從后端服務接收消息的代碼。而且用原始的代碼去編寫的轉發(為了使用沒有Kafka功能的nutzboot,沒有用spring的Kafka相關注解)。

5)主題:主題有一些限制,不能以/結尾,不支持通配符訂閱+

我當時還測試出了一些其他的問題,但是忘記了,而且這個項目竟然是上生產的項目……經歷過2萬設備連接,我在commitlog里面看到作者還寫“不知道Redis會不會有性能問題”這種提交信息……不過代碼真的非常非常清晰簡潔,有助于理解MQTT協議交互過程。

【推薦延伸閱讀】

MqttWk github 開源代碼

開源中國:MqttWk介紹

MqttWk 碼云 開源代碼

5、Jmqtt

【簡介】

image

jmqtt是一個大佬對開源Broker現狀不滿意,自己做出來的一個開源Broker。代碼思路很清晰,尤其對CONNECT做了優化,而且Session的過期處理得也很好,編寫了大量多線程代碼,看得出是Java多線程高手。

【官方文檔宣稱的特性】

完整的QoS等級

支持MQTT、Websocket連接方式

支持RocksDB進行數據本地存儲

【實際的使用限制分析】

不支持集群,不支持共享訂閱,不支持SSL,MessageQueue不是隊列……但是和大佬交流得最深,教了我很多東西,很感謝。

【推薦延伸閱讀】

jmqtt github源碼

jmqtt 中文自述

Ciciz:《MQTT Broker選型》

Ciciz:《IoT MQ設計篇:調研與協議選型》

Ciciz:《IoT MQ設計篇:開源or自研,系統復雜度分析》

Ciciz:《IoT MQ設計篇:基于開源項目二次開發的坑》

Ciciz:《IoT MQ設計篇:最終架構與jmqtt介紹》

6、Moquette 0.10

【簡介】

image

0.10和0.12是兩個核心版本,功能變化巨大,這里分開敘述。Moquette是我參考得最多的一個Broker了,它是唯一的功能齊全、Java語言編寫的開源Broker,網上很多人都是以Moquette為基礎進行開發的。Moquette怎么樣呢,以研究HiveMQ的“西安PP”大佬的原話說——就是一個玩具項目……看和HiveMQ截圖的源碼成熟度對比其實我也能感覺出來。但免費的玩具只有這一個啊,沒得挑。

【官方文檔宣稱的特性】

完整QoS服務

完整連接認證方式

多種持久化存儲支持

集群支持

性能監控支持

【實際的使用限制分析】

“專注的力量”用它的代碼進行壓測,發現有內存泄漏問題,于是自己修復了這些東西,還支持了Redis持久化,發布了一個開源版本irubant/moquette。moquette的集群只是用了hazelcast作消息總線,不支持共享訂閱,而且所有的消息都是廣播的,也沒有在不同Broker節點上相同clinetID相互踢下線的功能。沒有消息重發機制,只會在重連的時候重發。訂閱樹編寫得非常復雜,還不斷地以CAS(比較并替換)操作在并發環境下更換根節點,會帶來很多性能問題。

【推薦延伸閱讀】

moquttte源碼

moquette官網

專注的力量《開源MQTT中間件:moquette》

袁志健《從moquette源碼看IOT接入協議MQTT的實現》

7、Moquette 0.12

【簡介】

image

Moquette0.12將整個項目簡化了,Jar包管理方式從Maven改為Gradle,不再支持集群,說是為了讓人1分鐘就能快速上手,放棄了Hazelcast說這種方式做集群不好,準備先支持MQTT5.0,再考慮做集群的事情。不過這個版本改進了訂閱樹,還支持了重發未ACK的消息,MessageQueue也采用了Queue,去掉了大部分持久化方式,只保留H2。

【官方文檔宣稱的特性】

支持完整QoS

支持完整連接認證方式

【實際的使用限制分析】

完全地退化……不過代碼更清晰一點了,各個功能模塊劃分得更清楚。但是單機是最大的缺陷,很難改成集群,幾乎要全改。

8、其他

最近又出了一些新的Broker,例如基于moquette的cassandana,宣稱已經用于生產,還有一些新特性,想去看看源碼是怎么寫的。

至于Apache ActiveMQApache ActiveMQ Artemis這種基于消息隊列制作的MQTT Broker還沒有使用過,只是看了一些文章說有性能問題。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374