經測試過程發現moquette存在一些問題,已修改,可能是認識的問題,也可能是出發點不一樣。
總之,修改如下:
1. 修改消息隊列長度為32,避免了原來消息隊列超過最大條數之後,publish出錯的情況 修改了storage的構造函數,使其更通用
2. 修改了每次都對clientId的判定,針對client首次連結的情況 修改了離線消息簽收時的空指針異常 棄用了一些不常用的子產品
3. 添加了redis存儲實作 redis采用了現有conf配置機制 重新設計了session的存儲結構,以便後續添加分片處理
4. 修改工程的結構,獨立了common子產品,同時将redis,mapdb,broker建在common基礎上
5. 針對publish的記憶體洩漏,進行了修改(原本以為是netty洩露),經過兩天的不眠不休的調試,發現是moquette未回收導緻
使用說明文檔:
1.簡介
Moquette是一款開源的消息代理,整個系統基于java開發,以netty為基礎完整實作了MQTT協定的。
基于測試,moquette的用戶端承載量及消息的推送速度都比較客觀,在大批量頻繁短線上線的情景下,也可以承受。
Moquette代碼是完全開源的,測試過程中的問題進行了一定的修改,擴充實作了基于redis存儲的機制。
2.使用
Moquette所使用的配置檔案位于其根目錄下的config裡,包括以下:
acl.conf 權限配置
hazelcast.xml 叢集配置
password_file.conf 使用者密碼配置
moquette.conf 主配置
下面将詳細講解各配置檔案
基于檔案的權限配置較為複雜,以下為示例格式,将針對該示例具體說明。
1
2
3
4
5
6
7
8
[user admin] 訓示一個使用者admin。其後的條目,代表該使用者的相關topic的讀寫權限,一直到另一個user結束。
[topic write wifi/log] 代表隊wifi/log主題具有write權限,topic指令指定特定的主題名稱,不能帶有通配符。
[pattern write wifi/log/+] 使用通配符訓示符合規則的一定數量的topic的權限。
權限分類:
write
read
writeread
Moquette的叢集配置實用的是hazelcast。Hazelcast是基于java編寫的資料同步工具。在moquette中,用于不同節點消息的同步。
9
10
public-address:代表了目前節點的IP及端口
required-member:代表了叢集中的其他節點。
各節點的叢集模式建立後,各節點是對等關系,無主從之分
該檔案用于系統的可登入使用者,執行個體格式如下:
該檔案的格式非常簡單:
每行代表了一個使用者及其密碼,用:分割,密碼是sha256摘要後的結果。
關于client(消費者)所使用的使用者,大部分情況下,client隻需要其clientId來區分,是以背景可針對業務類型建立不同的使用者分給client使用,不需要為每個clientId都建立使用者。
主配置中包含了較多内容,介紹如下:
port 1883 是broker的主端口,預設為MQTT協定的1883端口
由于系統提供了websocket功能,可以使用websocket的方式使用(該模式未進行測試)。
對于有較高安全要求的系統,可以添加SSL支援。
storage_class io.moquette.persistence.redis.RedisStorageService
由于基于不同存儲的實作的性能,差異性較大,moquette預設采用記憶體存儲的模式,該模式有很高的性能,但存在單點崩潰下,消息丢失的風險(由于叢集負載的使用,可降低該問題發生的影響範圍)。
如果對存儲過于看重,性能可求次,可使用基于redis的存儲實作,其自帶的mapdb的存儲實作,錯誤較多。
在不設定的情況,預設采用的基于memory的存儲實作。
以上代表了,broker将以acl.conf中的内容為基礎進行授權鑒權。
以上代表不允許匿名通路,必須使用使用者名及密碼才可以通路。
以上代表broker将使用password檔案進行鑒權,若不需要則可以将其注釋掉。
在linux系統下,提供的epoll機制,可使系統能夠承載更高的終端。以上代表啟用epoll。在機器硬體較好的情況下,epoll模式提升明顯。
叢集配置的情況下,需要開啟以上配置,開啟配置的前提是hazelcast.xml檔案已配置。
在store_class已經配置為redis的情況下,需要配置以上參數,由于叢集模式使用hazelcast,目前的基于redis的實作,不具備分片等功能,但鍵值的設計已經具備。
Moquette代碼工程采用maven管理,采用maven install可以打包一個在linux下運作的檔案,打包後的格式如下:
Lib目錄是所有使用到的lib檔案,分為:
Netty相關
Hazelcast
Log相關
Redis存儲實作引入的lib:在使用memory的模式下,redis相關可以删除,減少包的大小。
Bin目錄:

linux下的moquette.sh啟動方式:
預設不是以背景運作的方式,需要使用以下指令運作:
nohup指令模式會找不到配置好的log輸出。
Windows下以bat指令運作
實作moqtt協定的用戶端存在很多種,針對該broker,目前測試使用的是eclipse-phao的,該用戶端實作提供了多種語言版本,便于不同終端使用。
可以在以下的網址中找到相關語言版本的下載下傳:http://www.eclipse.org/paho/downloads.php
針對不同的語言版本,可提供的功能存在不同,目前broker預設沒有實作除mqtt協定規範中提到的功能。
重連機制,需要用戶端想法實作該機制,避免用戶端掉線後隻能重新開機才能連結的境界。
3. 測試
該broker經過了多次測試。
測試場景:
<col>
記憶體
CPU
8G
4核
Client所運作機器多樣,每台機器運作5000個client。
Publish為普通windows機器,兩個publisher,每個5個發送線程,平均每秒100條消息。
10秒一條群發的情況下,測試3論。
每秒100條點對點的消息情況下,測試3輪。
每輪測試20到30幾個小時。
Client在clean Session的情況下,broker的記憶體占用較低,僅400M左右
在不清理會話的情況下,記憶體占用較高,在client大批量反複掉線重連情況下記憶體占用達到2G
心跳設定60s,過短(低于30s)的心跳,對broker來說不能承受。
搭建了兩個節點的叢集,通過nginx進行tcp負載,用戶端測試數量為3萬。
1.單broker從8000,15000,18000,25000幾個級别的測試,在不發送消息的情況下,這幾個級别的用戶端都可以連接配接。
承載量
結果
8000
OK
15000
18000
25000
2.在發送消息的情況
NG
在每10秒一條群發消息的情況下,單點broker的無掉線承載量是15000,18000發生較多的掉線情況。
在10秒一條群發消息及每秒100條點對點消息的發送情況下,消息的接受速度都在1秒以内。
基于實作分析,記憶體的占用主要由client在不清理會話進行連結掉線後産生的消息積累,在原有基于記憶體的實作機制中,為每個client儲存1024條消息,在超過1024條後,消息會導緻publish端出錯。修改後的實作,為每個離線client儲存最新的32條消息,超過32條的将被丢棄。
基于redis的實作,消息目前沒有設定棄用或過期機制。
測試期間的記憶體分析:
IP1的broker,總記憶體占用情況如下
記憶體穩定在800M左右,處于穩定狀态。
基于記憶體的存儲實作,目前僅儲存32條離線消息,超過32條将丢棄原有的。
遺願消息内容必須為ascii,不能為其他字元。遺願消息主要用于用戶端掉線後的處理。
用戶端的心跳不能設定過小,否則broker的承載量将嚴重下降,建議60s以上。
遺留的問題:
在心跳之間的時間段,測試發現存在broker誤簽收的情況。
以上問題,在業務實際使用過程中,采取業務簽收等方式,避免消息品質的不可靠性的出現。