李娜 陳福 朱建明 黃勇峰 張艷梅
摘?? 要:為了提高消息代理服務(wù)器在設(shè)備數(shù)量、傳輸消息數(shù)量增長(zhǎng)以及網(wǎng)絡(luò)環(huán)境復(fù)雜程度增加的情況下的傳輸效率,文章選擇Mosquitto作為MQTT的消息代理服務(wù)器,使用epoll機(jī)制代替poll機(jī)制,并對(duì)其訂閱樹的存儲(chǔ)結(jié)構(gòu)和遍歷過程進(jìn)行了優(yōu)化。提出了將鍵樹多重鏈表表示法中的分支結(jié)點(diǎn)思想應(yīng)用于訂閱樹結(jié)構(gòu)和使用了哈希表的方法來管理訂閱主題和訂閱者的思想。并提出了動(dòng)態(tài)空閑空間管理機(jī)制。測(cè)試結(jié)果顯示優(yōu)化之后的Mosquitto在高并發(fā)、高負(fù)荷下具有更高的性能。
關(guān)鍵詞:Mosquitto;MQTT通信協(xié)議;發(fā)布訂閱模式;哈希表;epoll機(jī)制
中圖分類號(hào):TP393.0????????? 文獻(xiàn)標(biāo)識(shí)碼:A
Analysis and optimization of MQTT data exchange protocol
Li Na ?Chen Fu? Zhu Jianming? Huang Yongfeng? Zhang Yanmei
Abstract: In order to improve the transmission efficiency of the message proxy server in the case of the number of devices, the number of transmitted messages, and the complexity of the network environment, This paper chose Mosquitto as the message proxy server of MQTT, using epoll mechanism instead of polling mechanism, and optimizing the storage structure and traversal process of its subscription tree. The idea of applying the branch node idea in the multi-linked list representation of the key tree to the subscription tree structure and using the hash table to manage the subscription topic and subscribers is proposed. And the dynamic free space management mechanism is proposed. The test results show that the optimized Mosquitto has higher performance under high concurrency and high load.
Key words: Mosquito; MQTT communication protocol; Publish and subscribe mode; Hash table; Epoll mechanism
1 引言
信息技術(shù)的發(fā)展不斷改變著人們的日常生活。特別是5G網(wǎng)絡(luò)的到來,物聯(lián)網(wǎng)技術(shù)正在影響著人類衣食住行的各個(gè)方面。從簡(jiǎn)單的智能可穿戴設(shè)備到智慧物流、農(nóng)業(yè)、工業(yè)、服務(wù)業(yè)等應(yīng)用中,可以看出物聯(lián)網(wǎng)技術(shù)有巨大的發(fā)展?jié)摿褪袌?chǎng)前景。無論從降本增效上,還是在提高人類生活質(zhì)量上,物聯(lián)網(wǎng)技術(shù)都占據(jù)著重要的作用[1~3][29]。
目前,物聯(lián)網(wǎng)在市場(chǎng)中的占比不斷增多,物聯(lián)網(wǎng)硬件設(shè)備的需求量也連續(xù)增長(zhǎng)。預(yù)計(jì)到2020年,全球物聯(lián)網(wǎng)設(shè)備的連接量會(huì)達(dá)到500億臺(tái)[4~6]。其中,占比最多的為移動(dòng)互聯(lián)網(wǎng)與智能終端的連接。所以,在數(shù)據(jù)傳輸方面功耗和性能都比較低。MQTT協(xié)議恰是為低帶寬、不穩(wěn)定網(wǎng)絡(luò)及計(jì)算和處置能力不足的設(shè)備所設(shè)計(jì)的,協(xié)議采用輕量型傳輸,耗費(fèi)電量小,能最大程度降低網(wǎng)絡(luò)流量開銷,達(dá)到最小化消息包并高效分配與傳輸[7~9]。隨著云計(jì)算和云存儲(chǔ)等網(wǎng)絡(luò)應(yīng)用的發(fā)展,如今的數(shù)據(jù)中心中的服務(wù)器節(jié)點(diǎn)數(shù)量已有百萬多個(gè)[10]。然而,目前的消息代理服務(wù)器并不能高效的管理數(shù)據(jù)流的傳輸,使得數(shù)據(jù)通信效率低下。所以,實(shí)現(xiàn)代理服務(wù)器的優(yōu)化,提高數(shù)據(jù)通信效率顯得尤為重要。
本文選擇Mosquitto作為MQTT的消息代理服務(wù)器,使用epoll機(jī)制代替poll機(jī)制[11],并對(duì)其訂閱樹的存儲(chǔ)結(jié)構(gòu)和遍歷過程進(jìn)行了優(yōu)化,提出了將鍵樹多重鏈表表示法中的分支結(jié)點(diǎn)思想應(yīng)用于訂閱樹結(jié)構(gòu)和使用了哈希表的方法來管理訂閱主題和訂閱者的思想。同時(shí),研究了Mosquitto[12]在用戶斷開連接時(shí)對(duì)空閑出來的空間進(jìn)行管理的情況,以及新用戶連接進(jìn)來時(shí)的處理過程,分析了目前這種管理方法存在的缺陷,提出了運(yùn)用指定長(zhǎng)度動(dòng)態(tài)數(shù)組的方法進(jìn)行空閑空間的管理。從而滿足復(fù)雜網(wǎng)絡(luò)環(huán)境或設(shè)備量劇增時(shí)數(shù)據(jù)流可以高效的進(jìn)行傳輸?shù)男枨蟆?/p>
2 相關(guān)工作
通過國(guó)內(nèi)外對(duì)于MQTT的研究可以看出,這些研究主要集中在對(duì)MQTT的應(yīng)用上,并且取得了一定的成果。但是對(duì)于傳輸消息的管理方面的研究卻少之又少。對(duì)通信消息的管理以及優(yōu)化可以節(jié)省通信時(shí)長(zhǎng),達(dá)到高效的消息傳輸。
在國(guó)外,由于物聯(lián)網(wǎng)技術(shù)起步比較早,所以針對(duì)MQTT的研究也比較多。有在發(fā)布訂閱機(jī)制方面的研究,也有在主題匹配算法領(lǐng)域的研究。其中,在主題匹配算法的研究上,Gough等人[13]提出了一種基于搜索樹的匹配算法,但是當(dāng)并行發(fā)送的請(qǐng)求增多時(shí)或者有請(qǐng)求取消時(shí),這種算法不能很好的對(duì)搜索樹進(jìn)行修改。Aguilera等人[14]同樣通過遍歷發(fā)布訂閱樹獲得匹配成功的訂閱請(qǐng)求,但是卻只將部分重復(fù)的謂詞考慮在內(nèi)。Silvia等人[15]將R-tree應(yīng)用于基于內(nèi)容的發(fā)布訂閱匹配中,并將三種R-tree變形用于基于內(nèi)容的數(shù)據(jù)傳輸中,在避免假陰性的同時(shí)也減少了假陽性的發(fā)生。Hu等人[16]研究了參數(shù)化空間文本訂閱的位置感知發(fā)布訂閱問題,提出了過濾器驗(yàn)證框架,有效的向相關(guān)訂閱者傳遞了消息。Guo等人[17]開發(fā)了一個(gè)高效的位置感知發(fā)布/訂閱系統(tǒng)Elaps,該系統(tǒng)使用R-tree進(jìn)行內(nèi)容匹配,當(dāng)移動(dòng)用戶的位置附近出現(xiàn)匹配事件時(shí),會(huì)迅速的通知給移動(dòng)用戶。
在國(guó)內(nèi),對(duì)于MQTT的研究也不斷增多,2007年第一次出現(xiàn)對(duì)于MQTT的研究,當(dāng)時(shí)國(guó)內(nèi)也只有一篇文章提到了MQTT,作者李強(qiáng)在多個(gè)Zigbee監(jiān)測(cè)網(wǎng)絡(luò)遠(yuǎn)程監(jiān)控的實(shí)現(xiàn)中通過MQTT協(xié)議實(shí)現(xiàn)管理應(yīng)用、監(jiān)測(cè)網(wǎng)絡(luò)中網(wǎng)關(guān)節(jié)點(diǎn)與中間層消息代理間的數(shù)據(jù)傳輸[18]。目前,對(duì)于MQTT的研究達(dá)到了上百篇。較多的文獻(xiàn)針對(duì)MQTT協(xié)議在消息推送領(lǐng)域的應(yīng)用進(jìn)行了探討和研究,以探討MQTT協(xié)議在教育、醫(yī)療、通信、農(nóng)業(yè)等領(lǐng)域的應(yīng)用[19~21]。具有代表性的文章來源于李宏等人[22],提出了基于MQTT的安卓手機(jī)防盜方法,測(cè)試表明該方法提高了安全性和可靠性。方霞[23]設(shè)計(jì)了基于MQTT的農(nóng)業(yè)物聯(lián)網(wǎng)消息推送系統(tǒng),實(shí)現(xiàn)了對(duì)農(nóng)業(yè)遠(yuǎn)程監(jiān)控的功能。崔自賞[24]將MQTT通信協(xié)議用于電梯監(jiān)控系統(tǒng),用來實(shí)現(xiàn)終端與云服務(wù)器之間的數(shù)據(jù)傳輸,將終端獲得的電梯實(shí)時(shí)狀態(tài)信息與故障情況上傳到遠(yuǎn)程服務(wù)器,可以達(dá)到對(duì)電梯進(jìn)行實(shí)時(shí)監(jiān)控的目的。
而且,國(guó)內(nèi)對(duì)于MQTT通信協(xié)議代理服務(wù)器的研究也不斷增多。 其中曾昂[25]等人提出了一款適合大文件傳輸?shù)膫鬏敺绞?,該方式以消息為主體,每個(gè)訂閱者共享一份拷貝,統(tǒng)一進(jìn)行發(fā)送,降低了內(nèi)存的占用空間。任亨以 Mosquitto、Redis等開源項(xiàng)目為基礎(chǔ)設(shè)計(jì)并實(shí)現(xiàn)了一個(gè)基于 MQTT 協(xié)議的消息推送服務(wù)器, 能夠?qū)τ脩粲嗛喌南⑦M(jìn)行推送, 還實(shí)現(xiàn)了用戶身份驗(yàn)證、ACL 權(quán)限檢查、自動(dòng)訂閱話題、熱點(diǎn)話題統(tǒng)計(jì)、服務(wù)器狀態(tài)監(jiān)控等功能[9]。
由此可見,隨著MQTT協(xié)議的逐漸成熟,該協(xié)議在互聯(lián)網(wǎng)通信行業(yè)扮演著越來越重要的角色。同時(shí),對(duì)于代理服務(wù)器內(nèi)部發(fā)布訂閱匹配機(jī)制的研究在國(guó)外也在不斷的完善,技術(shù)不斷成熟,為本課題的研究提供了大量的文獻(xiàn)基礎(chǔ)。
3 MQTT數(shù)據(jù)交換協(xié)議的優(yōu)化
3.1發(fā)布/訂閱模式優(yōu)化設(shè)計(jì)
發(fā)布/訂閱模式是一種消息轉(zhuǎn)發(fā)模式,在該模式中,消息的發(fā)布者和訂閱者并不需要直接建立通信,只需要通過中間的消息代理服務(wù)器進(jìn)行間接通信。中間的傳輸中介稱為節(jié)點(diǎn),也被成為主題(topic)。這種模式與TCP協(xié)議相比,解耦了用戶之間的依賴性。
在Mosquitto中,將所有的topic和客戶端的訂閱關(guān)系存放在訂閱樹中。對(duì)于不同的topic,Mosquitto根據(jù)/進(jìn)行分割,然后以樹形結(jié)構(gòu)的方式將這些片段相連,組成一棵訂閱樹。每個(gè)節(jié)點(diǎn)所對(duì)應(yīng)的topic為從根節(jié)點(diǎn)到該節(jié)點(diǎn)所組成的節(jié)點(diǎn)數(shù)。對(duì)于訂閱者來說,每個(gè)訂閱者的客戶端信息都掛在對(duì)應(yīng)的topic下邊。例如有如圖1所示的訂閱樹結(jié)構(gòu)。
如圖1所示的訂閱樹,其中每個(gè)節(jié)點(diǎn)都是一個(gè)topic分級(jí),每個(gè)節(jié)點(diǎn)對(duì)應(yīng)的訂閱topic由從根節(jié)點(diǎn)到當(dāng)前節(jié)點(diǎn)所經(jīng)過順序路徑節(jié)點(diǎn)組成。每個(gè)節(jié)點(diǎn)上連接的列表為訂閱從根節(jié)點(diǎn)到該節(jié)點(diǎn)組成主題的訂閱者列表。
在Mosquitto程序中,訂閱樹中存放的topic消息包括兩大類,為系統(tǒng)topic和業(yè)務(wù)topic。一般將存儲(chǔ)客戶端訂閱topic的樹命名為業(yè)務(wù)子樹,將保存客戶端連接信息的子樹命名為系統(tǒng)子樹。系統(tǒng) topic用于維護(hù)系統(tǒng)消息,業(yè)務(wù)topic用于維護(hù)客戶端訂閱的主題。Mosquitto程序代碼中mqtt3_handle_publish()函數(shù)內(nèi)存在一個(gè)字段retain,根據(jù)該字段的不同取值,這兩種類型的topic在生存周期、創(chuàng)建時(shí)間和存儲(chǔ)結(jié)果方面存在差異。
(1)Mosquitto中訂閱樹的創(chuàng)建
Mosquito程序在啟動(dòng)時(shí)就已經(jīng)創(chuàng)建好三個(gè)節(jié)點(diǎn),分別為總根節(jié)點(diǎn)、業(yè)務(wù)根節(jié)點(diǎn)和系統(tǒng)根節(jié)點(diǎn),如圖2所示。
其中,業(yè)務(wù)根節(jié)點(diǎn)和系統(tǒng)根節(jié)點(diǎn)為總根節(jié)點(diǎn)的子節(jié)點(diǎn),在創(chuàng)建開始,業(yè)務(wù)根節(jié)點(diǎn)和系統(tǒng)根節(jié)點(diǎn)中的topic存儲(chǔ)不同,業(yè)務(wù)根節(jié)點(diǎn)存的為空字符串,系統(tǒng)根節(jié)點(diǎn)中存的是字符串“$SYS”。訂閱樹的創(chuàng)建過程在mqtt3_db_open()函數(shù)中實(shí)現(xiàn)。
1)消息發(fā)布時(shí)搭建
在Mosquitto中,當(dāng)訂閱樹搭建部分為系統(tǒng)子樹或者是retain為1的消息發(fā)布時(shí)的業(yè)務(wù)子樹,在消息發(fā)布時(shí)都可以進(jìn)行搭建。以向系統(tǒng)topic:$SYS/broker/version發(fā)送版本消息“Mosquitto version 1.2”為例,搭建過程如下:
首先將發(fā)布的topic根據(jù)“/”進(jìn)行拆分,存儲(chǔ)到鏈表中。上述topic被拆分成$SYS、broker、version三個(gè)片段。
然后,找到對(duì)應(yīng)的子根節(jié)點(diǎn),根據(jù)總根節(jié)點(diǎn)的孩子節(jié)點(diǎn)中topic的存儲(chǔ)情況,找到存放內(nèi)容為$SYS的節(jié)點(diǎn)為系統(tǒng)子樹根節(jié)點(diǎn)。
其次,對(duì)子根節(jié)點(diǎn)的topic進(jìn)行遍歷,遍歷節(jié)點(diǎn)片段“$SYS”的下一個(gè)節(jié)點(diǎn)片段“broker”是否存在。如果不存在,需要產(chǎn)生一個(gè)新的節(jié)點(diǎn);如果已經(jīng)存在,繼續(xù)遍歷節(jié)點(diǎn)片段“broker”的下一個(gè)節(jié)點(diǎn)片段是否有“version”,無則添加,有則結(jié)束。添加節(jié)點(diǎn)在函數(shù)mqtt3_db_messages_queue()中調(diào)用函數(shù)_sub_add()實(shí)現(xiàn)。
最后,釋放掉存放topic片段的鏈表。
消息發(fā)布時(shí)訂閱樹的搭建流程如圖3所示。
2)消息訂閱時(shí)樹的搭建
當(dāng)retain字段值為0時(shí),業(yè)務(wù)子樹在有訂閱客戶端訂閱消息時(shí)才能創(chuàng)建。以訂閱客戶端向Mosquitto訂閱了topic:country/city/district為例,具體實(shí)現(xiàn)過程如下:
首先將訂閱的topic根據(jù)/進(jìn)行拆分,并放入鏈表中。上述topic被拆分成country、city、district三個(gè)片段。
然后,找到對(duì)應(yīng)的子根節(jié)點(diǎn),根據(jù)總根節(jié)點(diǎn)的孩子節(jié)點(diǎn)中topic的存儲(chǔ)情況,找到存放內(nèi)容為非$SYS的節(jié)點(diǎn)為業(yè)務(wù)子樹根節(jié)點(diǎn)。
其次,遍歷業(yè)務(wù)子樹中的topic是否與拆分的發(fā)布topic鏈表中的topic相同,如果不相同則為其添加該節(jié)點(diǎn)。具體過程在函數(shù)mqtt3_sub_add中實(shí)現(xiàn)。
最后,在所有訂閱節(jié)點(diǎn)存在于訂閱樹中之后,查看該主題的訂閱者是否存在,如果存在,將結(jié)點(diǎn)存入訂閱樹中,否則丟棄。釋放掉存放訂閱topic的鏈表。
3.2? Mosquitto中訂閱樹機(jī)制的分析與優(yōu)化
(1)優(yōu)化原因
Mosquito通過訂閱樹來管理主題和訂閱者。其對(duì)主題的管理是用“/”將主題分隔開并存儲(chǔ)到一棵訂閱樹中,從樹的根節(jié)點(diǎn)到任意一個(gè)節(jié)點(diǎn)所經(jīng)過的路徑為一條主題訂閱規(guī)則。每個(gè)節(jié)點(diǎn)都管理著該節(jié)點(diǎn)所對(duì)應(yīng)的訂閱列表,該列表中存儲(chǔ)了訂閱對(duì)應(yīng)主題客戶端的主要信息。所以訂閱主題的數(shù)量和分級(jí)直接決定了樹的形狀,從而影響操作效率。在Mosquitto中對(duì)訂閱樹的主要操作為查找、插入和刪除,這些操作都需要對(duì)訂閱樹的每一個(gè)層級(jí)進(jìn)行遍歷。
以插入為例,首先將訂閱主題的每個(gè)分級(jí)與訂閱樹每層的節(jié)點(diǎn)進(jìn)行對(duì)比,依次搜索相同的節(jié)點(diǎn),如果找到,則進(jìn)行下一級(jí)匹配,一直到所訂閱的主題全部匹配完成,然后將訂閱的內(nèi)容掛到對(duì)應(yīng)節(jié)點(diǎn)的訂閱者列表中。如果存在一些分級(jí)無法匹配成功,說明訂閱樹中還不存在該主題,需要將該主題中不匹配的節(jié)點(diǎn)加入到訂閱樹中,然后將訂閱內(nèi)容掛到當(dāng)前生成的節(jié)點(diǎn)的訂閱者列表中。具體匹配流程如圖4所示。
如果訂閱主題當(dāng)前的分級(jí)不為空,同時(shí)能夠匹配上訂閱樹中節(jié)點(diǎn)中的內(nèi)容,則進(jìn)行下一個(gè)分級(jí)內(nèi)容的比較。如果訂閱主題當(dāng)前的分級(jí)不為空,但是不能匹配上訂閱樹中節(jié)點(diǎn)中的內(nèi)容,需要為訂閱樹當(dāng)前分級(jí)插入一個(gè)節(jié)點(diǎn),繼續(xù)以插入節(jié)點(diǎn)為根節(jié)點(diǎn)進(jìn)行下一層級(jí)的匹配。如果訂閱主題列表為空,將訂閱主題的內(nèi)容掛到訂閱列表中。
Mosquito采用的這種訂閱樹的發(fā)布/訂閱模式可以提供清晰的邏輯,有利于開發(fā)和維護(hù)。但是每一個(gè)客戶端的訂閱和發(fā)布過程都需要對(duì)樹進(jìn)行遍歷,當(dāng)樹極其龐大,特別是訂閱客戶端網(wǎng)絡(luò)連接狀況差時(shí)的頻繁重連操作,對(duì)訂閱樹的遍歷操作不斷增加,降低了運(yùn)行效率。
(2)優(yōu)化方案
1)優(yōu)化方案一
對(duì)于Mosquitto中訂閱樹搜索時(shí)存在的缺陷,使用鍵樹的思想進(jìn)行優(yōu)化。主要優(yōu)化方案是在訂閱樹根節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)建立索引,索引為a-z的26個(gè)字母,第27個(gè)為其他字符,方便起見,存字母‘z的ASCII的下一個(gè)值‘{。
鍵樹,又被稱為數(shù)字查找樹,它是一棵度大于等于2的樹,樹中的每個(gè)節(jié)點(diǎn)只包含組成關(guān)鍵字的符號(hào),并不是一個(gè)或幾個(gè)關(guān)鍵字。如關(guān)鍵字是數(shù)值,則節(jié)點(diǎn)中存儲(chǔ)的為一個(gè)數(shù)位;如果關(guān)鍵字為單詞,則節(jié)點(diǎn)中存儲(chǔ)的為單詞的字母字符。這種樹形的結(jié)構(gòu)會(huì)給類型為關(guān)鍵字查找的表帶來方便。
鍵樹有兩種存儲(chǔ)結(jié)構(gòu),樹的孩子兄弟鏈表存儲(chǔ)和樹的多重鏈表存儲(chǔ)。其中樹的多重鏈表存儲(chǔ)又叫做Trie樹。若從鍵樹中某個(gè)結(jié)點(diǎn)到葉子結(jié)點(diǎn)的路徑上每個(gè)結(jié)點(diǎn)都只有一個(gè)孩子,則可將該路徑上所有結(jié)點(diǎn)壓縮成一個(gè)“葉子結(jié)點(diǎn)”,且在該葉子節(jié)點(diǎn)中存儲(chǔ)關(guān)鍵字及指向記錄的指針等信息。
根據(jù)鍵樹中分支節(jié)點(diǎn)中的存儲(chǔ)思想,將發(fā)布訂閱樹中的業(yè)務(wù)根節(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)設(shè)置為27個(gè),存儲(chǔ)從a-z的26個(gè)字符,第27個(gè)結(jié)點(diǎn)存儲(chǔ)為其他字符。具體結(jié)構(gòu)圖如圖5所示。
具體實(shí)現(xiàn)
首先,初始化業(yè)務(wù)子樹的第一層葉子結(jié)點(diǎn)
然后,獲取topic第一個(gè)片段的首字母,全變?yōu)樾懽帜?,如果是a-z之間的英文字符,則進(jìn)入對(duì)應(yīng)的結(jié)點(diǎn)進(jìn)行查找,否則進(jìn)入第27個(gè)結(jié)點(diǎn)進(jìn)行查找。
最后topic進(jìn)行匹配查找,查找過程與原始Mosquitto相同,在函數(shù)_sub_search中完成。
2)優(yōu)化方案二
根據(jù)Mosquitto中訂閱樹存在的缺陷,對(duì)Mosquitto的發(fā)布訂閱機(jī)制進(jìn)行優(yōu)化。主要優(yōu)化方法為將訂閱樹的存儲(chǔ)方式變?yōu)楣1泶鎯?chǔ)。哈希表是通過關(guān)鍵碼值對(duì)表直接進(jìn)行訪問的數(shù)據(jù)結(jié)構(gòu),也稱為散列表。為了快速對(duì)表進(jìn)行查找,通過算法函數(shù)將關(guān)鍵碼值映射到表中的一個(gè)位置,而這個(gè)算法函數(shù)也稱為散列函數(shù)或哈希函數(shù)。
本文使用哈希表存儲(chǔ)主要是為了能夠根據(jù)訂閱主題快速查找到主題訂閱者列表。有學(xué)者已經(jīng)使用哈希表存儲(chǔ)訂閱主題和訂閱者列表[26-27]。哈希表中的key值為訂閱者訂閱的主題,內(nèi)容是從根節(jié)點(diǎn)到當(dāng)前節(jié)點(diǎn)所組成的topic;value值為每個(gè)主題對(duì)應(yīng)的訂閱者列表的地址。哈希表組成如圖6所示。
但是上述存儲(chǔ)方式也存在一定的缺陷,當(dāng)訂閱主題量劇增,哈希表長(zhǎng)度較長(zhǎng)時(shí),在匹配訂閱主題時(shí),需要進(jìn)行較多的主題查找,效率低下。
本文提出在哈希表前邊添加一個(gè)鏈表進(jìn)行索引。首先,將訂閱主題的第一個(gè)節(jié)點(diǎn)根據(jù)首字母進(jìn)行分組,將大寫字母統(tǒng)一變?yōu)樾懽帜?,將第一個(gè)節(jié)點(diǎn)為非字母的分為一組;然后,申請(qǐng)一個(gè)長(zhǎng)度為27的鏈表,前26個(gè)存儲(chǔ)的為主題節(jié)點(diǎn)首字母為‘a(chǎn)-z的哈希表的開始地址,第27個(gè)為主題節(jié)點(diǎn)為非字母的其他節(jié)點(diǎn)開始地址。具體實(shí)現(xiàn)方式如圖7所示。
(3)優(yōu)化實(shí)現(xiàn)
訂閱機(jī)制的優(yōu)化主要集中在文件subs.c中,具體則涉及以下接口函數(shù)。
為了實(shí)現(xiàn)本次優(yōu)化,在subs.c文件中添加了對(duì)哈希表操作的函數(shù),和一個(gè)哈希表結(jié)構(gòu)體。
struct my_struct{
char *name;
struct _mosquitto_subhier *sub_node;
UT_hash_handle hh;
};
其中,name是鍵(key);sub_node是值,保存結(jié)構(gòu)體指針類型的節(jié)點(diǎn);hh是內(nèi)部使用的哈希處理句柄,只需要定義該變量,并不需要進(jìn)行賦值。
首先,初始化一個(gè)空的哈希表為g_hash_topic_table,接下來為對(duì)哈希表的操作的主要函數(shù)。
其中,函數(shù)get_node_by_topic根據(jù)訂閱主題調(diào)用HASH_FIND_STR函數(shù)獲得訂閱節(jié)點(diǎn)。
函數(shù)get_address_by_topic根據(jù)訂閱主題首字母獲取索引列表中存放的哈希表地址。
函數(shù)set_hash_topic調(diào)用HASH_ADD_KEYPTR函數(shù)實(shí)現(xiàn)對(duì)topic的添加。
函數(shù)del_node_by_topic調(diào)用HASH_DEL函數(shù)完成對(duì)節(jié)點(diǎn)的刪除操作。
函數(shù)clear_hash_topic_table首先通過HASH_ITER對(duì)節(jié)點(diǎn)進(jìn)行遍歷,然后調(diào)用HASH_DEL刪除節(jié)點(diǎn)。
函數(shù)db_messages_quick_queue實(shí)現(xiàn)對(duì)節(jié)點(diǎn)的查找并添加,例如發(fā)布消息給主題a/b/c,需要尋找a/#,a/b/#,a/b/c/#,a/b/c等結(jié)構(gòu)。然后調(diào)用set_hash_topic實(shí)現(xiàn)節(jié)點(diǎn)添加。
函數(shù)send_topic實(shí)現(xiàn)對(duì)消息的發(fā)送功能。
同時(shí)在原有函數(shù)中對(duì)以上函數(shù)進(jìn)行調(diào)用,改變了原有函數(shù)的功能。其中在函數(shù)mqtt3_sub_add中,主要完成訂閱操作,首先根據(jù)訂閱主題首字母獲得哈希表中該主題可能所在地址范圍,然后查看哈希表中是否存在該訂閱主題,如果存在,則將訂閱內(nèi)容掛載到訂閱列表中,如果不存在,則新建一個(gè)結(jié)構(gòu)體存儲(chǔ)訂閱主題,訂閱內(nèi)容掛到該主題的訂閱列表中。
函數(shù)mqtt3_db_messages_queue主要實(shí)現(xiàn)消息發(fā)布操作,對(duì)發(fā)布主題進(jìn)行拆分,搜索以‘#結(jié)尾的子主題是否在哈希表中,如果存在則進(jìn)行發(fā)送。
函數(shù)mqtt3_sub_remove和mqtt3_subs_clean_session主要實(shí)現(xiàn)清除哈希表中的context功能,首先查找該context對(duì)應(yīng)的訂閱主題是否存在于哈希表中,如果存在,則刪除context,如果不存在,則直接返回。
函數(shù)mqtt3_retain_queue實(shí)現(xiàn)對(duì)context列表的保存操作,只需要根據(jù)context對(duì)應(yīng)的訂閱主題在哈希表中找到該context,然后調(diào)用函數(shù)_retain_process實(shí)現(xiàn)context的保存。
3.2 空閑空間管理機(jī)制優(yōu)化
Mosquitto中并沒有實(shí)現(xiàn)對(duì)空閑空間進(jìn)行管理。當(dāng)有連接斷開時(shí),將空閑出數(shù)組上的位置,等待有新的連接進(jìn)來時(shí),需要掃描整個(gè)context,如果找到位置則存放新產(chǎn)生的context,否則調(diào)用realloc函數(shù)創(chuàng)建一個(gè)空間。這種遍歷查詢context會(huì)使業(yè)務(wù)處理效率低下,并且realloc每次只分配一個(gè)內(nèi)存空間,當(dāng)有大量的連接進(jìn)來時(shí),并且沒有空閑數(shù)組時(shí),需要多次調(diào)用realloc函數(shù);當(dāng)存在大量的連接斷開時(shí),數(shù)組就會(huì)空閑出多個(gè)位置,造成資源的浪費(fèi)。
針對(duì)上述問題,并參考相關(guān)學(xué)者的優(yōu)化[28],在前人優(yōu)化的基礎(chǔ)上設(shè)置了最大空閑空間數(shù),減少了資源的浪費(fèi)。
首先,添加一個(gè)動(dòng)態(tài)數(shù)組,用來存放空閑context的地址。
當(dāng)有新的連接進(jìn)來時(shí),先在這個(gè)數(shù)組中查找是否有空閑的地址,如果有,直接插入,同時(shí)把動(dòng)態(tài)數(shù)組中的索引地址刪掉。
如果沒有則調(diào)用realloc函數(shù)創(chuàng)建多個(gè)空間。例如1000個(gè),然后將這些空間的地址放入動(dòng)態(tài)數(shù)組中。
當(dāng)存在大量的連接斷開時(shí),服務(wù)器就會(huì)存在大量的空閑空間,動(dòng)態(tài)數(shù)組中存放了大量的地址索引,增加判定動(dòng)態(tài)數(shù)組長(zhǎng)度的功能,當(dāng)達(dá)到一定的長(zhǎng)度之后(例如10000個(gè)),將多余的地址所指向的空閑空間釋放掉,維持一個(gè)較少量的空閑空間數(shù)。
4 測(cè)試與分析
為了驗(yàn)證對(duì)MQTT服務(wù)器Mosquitto優(yōu)化之后的功能和性能,本章節(jié)對(duì)優(yōu)化之后的Mosquitto進(jìn)行測(cè)試。主要測(cè)試優(yōu)化后Mosquitto能否實(shí)現(xiàn)發(fā)布訂閱功能;對(duì)比優(yōu)化前后Mosquitto在性能方面的變化,并對(duì)測(cè)試結(jié)果進(jìn)行分析。
4.1 測(cè)試環(huán)境
測(cè)試環(huán)境包括硬件環(huán)境和軟件環(huán)境。硬件環(huán)境的服務(wù)器內(nèi)存大小為8GB,固態(tài)硬盤為256GB;虛擬機(jī)的內(nèi)存為1GB、硬盤為20GB。軟件環(huán)境中虛擬機(jī)操作系統(tǒng)為ubuntu-14.04.4-desktop-amd64;Mosquitto版本為1.01;測(cè)試工具為mqtt-benchmark。功能測(cè)試為局域網(wǎng),性能測(cè)試為公共網(wǎng),帶寬為電信100Mbps。
4.2 測(cè)試內(nèi)容與分析
(1)功能測(cè)試
首先檢測(cè)能否開啟Mosquitto服務(wù)器,其次檢測(cè)能否完成消息的訂閱發(fā)布功能。功能測(cè)試使用回送地址進(jìn)行,實(shí)驗(yàn)設(shè)置開四個(gè)終端,其中一個(gè)終端負(fù)責(zé)開啟服務(wù)器,一個(gè)終端負(fù)責(zé)發(fā)布消息,兩個(gè)終端負(fù)責(zé)訂閱消息。運(yùn)行結(jié)果如圖9至圖12所示。
通過上圖的實(shí)驗(yàn)結(jié)果可以得到優(yōu)化之后的mosquitto可以實(shí)現(xiàn)開啟服務(wù)的功能,并且可以進(jìn)行對(duì)不同的訂閱主題進(jìn)行發(fā)布消息。訂閱客戶端也可以獲得訂閱消息。
(2)性能測(cè)試
性能測(cè)試通過使用測(cè)試工具mqtt-benchmark進(jìn)行。對(duì)于虛擬機(jī),192.168.226.136上用emqttd_benchmark測(cè)試,192.168.226.129上的Mosquitto服務(wù)器。
1)測(cè)試一
測(cè)試不同QoS級(jí)別下,原始Mosquitto與優(yōu)化之后的Mosquitto在平均運(yùn)行時(shí)長(zhǎng),平均時(shí)延方面的性能對(duì)比。實(shí)驗(yàn)設(shè)置10個(gè)發(fā)送客戶端,每個(gè)客戶端發(fā)送1000條消息,訂閱客戶端數(shù)量為1000,QoS分別為0,1,2情況下的結(jié)果圖如圖13所示。
從圖中運(yùn)行結(jié)果對(duì)比,隨著QoS的增大,平均運(yùn)行時(shí)長(zhǎng)和平均時(shí)延不斷增大,但是時(shí)延標(biāo)準(zhǔn)差總體成減小趨勢(shì),說明隨著QoS的增大,傳輸越來越穩(wěn)定。這是由于QoS越大,需要進(jìn)行報(bào)文交換的次數(shù)也越多,導(dǎo)致服務(wù)器的性能以及網(wǎng)絡(luò)負(fù)載增大,使得運(yùn)行時(shí)長(zhǎng)和時(shí)延增大,同時(shí),時(shí)延也越穩(wěn)定,符合預(yù)期設(shè)想。
此外,在三種級(jí)別的QoS情況下,優(yōu)化之后的Mosquitto在平均運(yùn)行時(shí)長(zhǎng)和平均時(shí)延方面都要優(yōu)于原始Mosquitto,所以優(yōu)化之后的Mosquitto服務(wù)器在運(yùn)行速度上有所提升。但是在時(shí)延穩(wěn)定性方面,優(yōu)化之后的Mosquitto服務(wù)器還存在改進(jìn)的空間。同時(shí),根據(jù)QoS在不同級(jí)別下的性能,可以得出在QoS要求不高的場(chǎng)景下,可以使用低級(jí)別的QoS來進(jìn)行消息的傳輸,使得系統(tǒng)性能增大。
2)測(cè)試二
在QoS級(jí)別為0的情況下,測(cè)量不同消息發(fā)布數(shù)量情況下Mosquitto服務(wù)器的時(shí)延變化情況以及吞吐量情況。實(shí)驗(yàn)設(shè)置20個(gè)發(fā)送客戶端,每個(gè)客戶端發(fā)送10000、20000、30000、40000、50000、60000、70000個(gè)消息。
如圖14所示,平均運(yùn)行時(shí)長(zhǎng)結(jié)果相差較小,但是原始的Mosquitto運(yùn)行時(shí)的平均時(shí)延要大于優(yōu)化之后的Mosquitto。
3)測(cè)試三
在QoS級(jí)別為0的情況下,測(cè)試同時(shí)在線時(shí)不同數(shù)量發(fā)送客戶端情況下,運(yùn)行時(shí)間、發(fā)送時(shí)延情況。實(shí)驗(yàn)設(shè)置每個(gè)客戶端發(fā)送一條消息,分別測(cè)試發(fā)送客戶端數(shù)量為1000、5000、10000、15000、20000。
如圖15所示對(duì)比結(jié)果,當(dāng)在線用戶數(shù)量較少時(shí),原始的Mosquitto在平均運(yùn)行時(shí)長(zhǎng)、平均時(shí)延、最大時(shí)延要小于優(yōu)化之后的Mosquitto,并且傳輸穩(wěn)定性也要高,性能上優(yōu)于優(yōu)化之后的Mosquitto,但是當(dāng)活躍用戶量增大時(shí),優(yōu)化之后的Mosquitto開始表現(xiàn)出較好的性能。
4)測(cè)試四
在QoS級(jí)別為0的情況下,測(cè)試每條信息在不同字節(jié)大小的情況下消息發(fā)送的情況,如圖16所示。實(shí)驗(yàn)設(shè)置發(fā)送客戶端數(shù)為20,每個(gè)客戶端發(fā)送10條消息,發(fā)送消息大小分別為100b、1000b、10000b、100000b、1000000b、10000000b。
如表1、表2所示,當(dāng)發(fā)送消息字節(jié)比較少的時(shí)候原始Mosquitto的發(fā)送平均時(shí)延要小于優(yōu)化之后的,同時(shí)穩(wěn)定性也更好,平均吞吐量也比較大,但是當(dāng)發(fā)送消息字節(jié)數(shù)增大時(shí),優(yōu)化之后的Mosquitto在平均時(shí)延以及穩(wěn)定性方面都優(yōu)于原始的Mosquitto,并且吞吐量也更大。
綜上所述,優(yōu)化之后的Mosquitto在發(fā)送客戶端數(shù)量、發(fā)送消息數(shù)量以及消息字節(jié)較大的時(shí)候,都要優(yōu)于原始的Mosquitto,但是穩(wěn)定性方面需要進(jìn)一步的提升。
4 結(jié)束語
本文通過對(duì)MQTT協(xié)議的深入學(xué)習(xí),以及MQTT消息代理服務(wù)器Mosquitto的研究,詳細(xì)介紹了對(duì)于Mosquitto服務(wù)器內(nèi)部功能實(shí)現(xiàn)的優(yōu)化。首先,對(duì)MQTT協(xié)議中的關(guān)鍵點(diǎn)進(jìn)行學(xué)習(xí);其次,分析了Mosquitto的訂閱/發(fā)布模式中的訂閱樹,提出了帶分支節(jié)點(diǎn)訂閱樹和利用帶分區(qū)的哈希表代替訂閱樹兩種優(yōu)化思想;然后,分析了Mosquitto中空閑空間遍歷情況,提出了指定長(zhǎng)度的動(dòng)態(tài)數(shù)組存儲(chǔ)空閑空間列表。最后,本文根據(jù)以上提出的思想進(jìn)行測(cè)試,驗(yàn)證了優(yōu)化之后的Mosquitto在負(fù)載較大的情況下更加高效。
雖然目前實(shí)現(xiàn)了對(duì)Mosquitto底層代碼優(yōu)化設(shè)計(jì),但是根據(jù)測(cè)試過程中遇到的問題,本項(xiàng)目還有一些不足的地方,需要作為下一步的工作繼續(xù)改進(jìn)。
(1)由于開發(fā)時(shí)間緊張,導(dǎo)致一些功能還未進(jìn)行添加,影響服務(wù)器的性能和穩(wěn)定性。特別是在實(shí)際的網(wǎng)絡(luò)環(huán)境中運(yùn)行情況復(fù)雜,容易發(fā)生異常情況,需要增加日志記錄功能和完善異常處理機(jī)制。
(2)缺少對(duì)每個(gè)優(yōu)化情況的效果進(jìn)行對(duì)比分析,需要分析各種優(yōu)化情況對(duì)于性能改進(jìn)的貢獻(xiàn)比例,然后根據(jù)比例情況進(jìn)行再次優(yōu)化調(diào)整,不斷提高M(jìn)osquitto的性能。
(3)對(duì)Mosquitto服務(wù)器安全方面沒有進(jìn)行考慮,需要提高安全認(rèn)證機(jī)制。
(4)對(duì)Mosquitto還可以進(jìn)行更加深入的擴(kuò)展研究。針對(duì)不同的場(chǎng)景可以提出更好的優(yōu)化方法。
基金項(xiàng)目:
1.國(guó)家自然科學(xué)基金(項(xiàng)目編號(hào):61672104);
2.國(guó)家自然科學(xué)基金(項(xiàng)目編號(hào):U1509214);
3.國(guó)家自然科學(xué)基金(項(xiàng)目編號(hào):61702570)。
參考文獻(xiàn)
[1] ?弭寶瞳,梁循,張樹森.社交物聯(lián)網(wǎng)研究綜述[J].計(jì)算機(jī)學(xué)報(bào),2018,41(07):1448-1475.
[2] ?張玉清,周威,彭安妮.物聯(lián)網(wǎng)安全綜述[J].計(jì)算機(jī)研究與發(fā)展,2017,54(10):2130-2143.
[3] ?Ganzha M, Paprzycki M, Paw?owski W, et al. Semantic interoperability in the Internet of Things; an overview from the INTER-IoT perspective ☆[J]. Journal of Network & Computer Applications, 2016, 81.
[4] ?Majchrzak T A, Groenli T M. Introduction to the Minitrack on Software Development for Mobile Devices, Wearables, and the Internet-of-Things[C]// Hawaii International Conference on System Sciences. 2018.
[5] ?Ghanbari A, Laya A, Alonso-Zarate J, et al. Business Development in the Internet of Things: A Matter of Vertical Cooperation[J]. IEEE Communications Magazine, 2017, 55(2):135-141.
[6] ?Stolpe M. The Internet of Things: Opportunities and Challenges for Distributed Data Analysis[M]. ACM, 2016.
[7] ?Handosa M, Gra?anin D, Elmongui H G. Performance evaluation of MQTT-based internet of things systems[C]// Simulation Conference. IEEE, 2018:4544-4545.
[8] ?楊鵬.基于MQTT協(xié)議的信息推送平臺(tái)系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[D].成都:電子科技大學(xué),2015.
[9] ?Lee S , Kim H , Hong D K , et al. Correlation analysis of MQTT loss and delay according to QoS level[C]// Information Networking (ICOIN), 2013 International Conference on. IEEE Computer Society, 2013.
[10] ?黃建洋,蘭巨龍,胡宇翔,馬騰.一種基于分段路由的多路徑流傳輸機(jī)制[J].電子學(xué)報(bào),2018,46(06):1488-1495.
[11] ?任亨,馬躍,楊海波,賈正鋒.基于MQTT協(xié)議的消息推送服務(wù)器[J].計(jì)算機(jī)系統(tǒng)應(yīng)用,2014,23(03):77-82.
[12] ?Baidu Inc. Mosquitto[OL]. http://baike.baidu.com/view/9923983.htm?fr=aladdin.
[13] ?Gough J, Smith G. Efficient recognition of events in a distributed system// Proceedings of the Australasian Computer Science Conference. Canberra, Australia, 1995: 173-179.
[14] ?Aguilera M K, Strom R E, Sturman D C, et al. Matching events in a content-based subscription system// Proceedings of the 18th ACM Symposium on Principles of Distributed Computing. Georgia, USA, 1999: 53-61.
[15] ?Bianchi S , Felber P , Gradinariu M . Content-based Publish/Subscribe using Distributed R-trees[J]. Lecture Notes in Computer Science, 2007:537-548.
[16] ?Hu H , Liu Y , Li G , et al. [IEEE 2015 IEEE 31st International Conference on Data Engineering (ICDE) - Seoul, South Korea (2015.4.13-2015.4.17)] 2015 IEEE 31st International Conference on Data Engineering - A location-aware publish/subscribe framework for parameterized spatio-textual subscriptions[C]// IEEE International Conference on Data Engineering. IEEE, 2015:711-722.
[17] ?Guo L , Chen L , Zhang D , et al. Elaps: An efficient location-aware pub/sub system[C]// IEEE International Conference on Data Engineering. IEEE, 2015.
[18] ?李強(qiáng).多個(gè)Zigbee監(jiān)測(cè)網(wǎng)絡(luò)遠(yuǎn)程監(jiān)控的實(shí)現(xiàn)[J].微計(jì)算機(jī)信息,2007(07):141-143.
[19] ?蔣鵬,袁嵩.基于MQTT協(xié)議的綜合消息推送[J].現(xiàn)代計(jì)算機(jī)(專業(yè)版),2014(11):11-15+21.
[20] ?姜妮,張宇,趙志軍.基于MQTT物聯(lián)網(wǎng)消息推送系統(tǒng)[J].網(wǎng)絡(luò)新媒體技術(shù).2014(6):62-64.
[21] ?賈軍營(yíng),王月鵬,王少華.基于MQTT協(xié)議IM的研究和實(shí)現(xiàn)[J].計(jì)算機(jī)系統(tǒng)應(yīng)用.2015(07):9-14.
[22] ?李宏,郭江波.基于MQTT協(xié)議的Android手機(jī)防盜方法[J].無線電工程,2018,48(05):357-361.
[23]?方霞.基于MQTT協(xié)議的農(nóng)業(yè)物聯(lián)網(wǎng)消息推送系統(tǒng)[J].計(jì)算機(jī)技術(shù)與發(fā)展,2018,28(09):168-171.
[24] ?崔自賞,陳冰,艾武,黃明強(qiáng).基于MQTT協(xié)議的物聯(lián)網(wǎng)電梯監(jiān)控系統(tǒng)設(shè)計(jì)[J].電子測(cè)量技術(shù),2018,41(07):114-119.
[25] ?曾昂,李寧,嚴(yán)俊.Mosquitto大文件傳輸方式的研究與改進(jìn)[J].計(jì)算機(jī)工程與應(yīng)用,2017,53(04):123-127.
[26] ?鄭峰.基于MQTT的云推送平臺(tái)的研究及應(yīng)用[D].杭州:杭州電子科技大學(xué),2016.
[27] ?逍遙子_. Mosquitto的優(yōu)化[OL]. https://blog.csdn.net/houjixin/article/details/46413783.
[28] ?逍遙子_. Mosquitto的優(yōu)化[OL].?? https://blog.csdn.net/houjixin/article/details/46413941.
[29] ?劉志誠(chéng).物聯(lián)網(wǎng)網(wǎng)絡(luò)信息安全生態(tài)體系構(gòu)建新論[J].網(wǎng)絡(luò)空間安全,2018,9(12):85-89.