蒲鳳平, 陳建政
(西南交通大學(xué)牽引動(dòng)力國(guó)家重點(diǎn)實(shí)驗(yàn)室, 成都 610031)
近年來(lái),隨著互聯(lián)網(wǎng)的飛速發(fā)展,大型的分布式系統(tǒng)得到了前所未有的發(fā)展?!霸朴?jì)算”,SOA等的出現(xiàn)成為分布式系統(tǒng)發(fā)展過(guò)程中的重要里程碑[1]。在一個(gè)分布式系統(tǒng)中,一組獨(dú)立的計(jì)算機(jī)展現(xiàn)給用戶的是一個(gè)統(tǒng)一的整體,就好象是一個(gè)系統(tǒng)似的。通常,對(duì)用戶來(lái)說(shuō),分布式系統(tǒng)只有一個(gè)模型或范型。在操作系統(tǒng)之上有一層軟件中間件負(fù)責(zé)實(shí)現(xiàn)這個(gè)模型[2]。消息隊(duì)列中間件ZeroMQ[3]在兩年前推出,它具有很多方便分布式系統(tǒng)架構(gòu)的特點(diǎn),可支持任意大的應(yīng)用程序。ZeroMQ不是簡(jiǎn)單的點(diǎn)對(duì)點(diǎn)交互,相反,它定義了分布式系統(tǒng)的全局拓?fù)?。ZeroMQ應(yīng)用程序沒(méi)有鎖,可并行運(yùn)行。此外,它可在多個(gè)線程、內(nèi)核和主機(jī)盒之間彈性伸縮。ZeroMQ現(xiàn)在還在不斷更新中,但因它比同類(lèi)產(chǎn)品有很多優(yōu)勢(shì),逐漸被人們認(rèn)識(shí),得到很多好評(píng)。
ZeroMQ將網(wǎng)絡(luò)異常、異步、緩沖區(qū)、多線程等都封裝起來(lái)了,并且,ZeroMQ以消息為單位進(jìn)行收發(fā),這樣省卻了很多代碼;ZeroMQ的API(Application Program Interface 應(yīng)用程序接口)很少,上手容易。ZeroMQ的消息格式如圖1[5]所示。
ZeroMQ以統(tǒng)一接口支持多種底層通信方式:線程間通信,進(jìn)程間通信,跨主機(jī)通信。比如,如果要把多進(jìn)程軟件用跨主機(jī)的環(huán)境中,只需要將通信協(xié)議由“ipc://xxx”改為”tcp://*.*.*.*.*:****”即可,而不需要改動(dòng)其余代碼[6]。
圖1 消息格式
ZeroMQ支持4類(lèi)通訊模式:請(qǐng)求回應(yīng)模式、發(fā)布訂閱模式、管道模式以及信號(hào)模式,其中,前3種模式使用較多,信號(hào)模式使用較少,主要是用來(lái)支持傳統(tǒng)的TCP socket模型。用這4種模式不僅可以實(shí)現(xiàn)傳統(tǒng)的一對(duì)一的通訊,還能實(shí)現(xiàn)一對(duì)多,甚至多對(duì)多的通訊。
ZeroMQ有超過(guò)20種以上的開(kāi)發(fā)語(yǔ)言綁定,諸如C、C++、Java、.NET、Python等,支持絕大多數(shù)的操作系統(tǒng),例如Linux, Windows,OS X,如果開(kāi)發(fā)的分布式系統(tǒng)比較復(fù)雜,常常不會(huì)只是一種語(yǔ)言或者一種平臺(tái),ZeroMQ跨語(yǔ)言、跨平臺(tái)的特性就顯得很重要了。
1)RabbitMQ: 采用Erlang開(kāi)發(fā)的,支持完善AMQP(Advanced Message Queuing Protocol,高級(jí)消息隊(duì)列協(xié)議);支持消息持久化和崩潰恢復(fù),應(yīng)用程序在重新啟動(dòng)之后消息不會(huì)丟失。它通過(guò)代理的模式實(shí)現(xiàn)分布式系統(tǒng),這種模式使系統(tǒng)的規(guī)模伸縮性會(huì)比較差,并且會(huì)降低系統(tǒng)效率,因?yàn)橹醒牍?jié)點(diǎn)增加了延遲也讓消息的封裝更多[7]。
2)ActiveMQ: 支持STOMP(流文本定向消息協(xié),Streaming Text Orientated Message Protocol),有很長(zhǎng)的使用歷史,并且被廣泛使用。容易實(shí)現(xiàn)很多高級(jí)的技術(shù),但是常常是以它的性能為代價(jià),這對(duì)消息傳輸來(lái)說(shuō)是一個(gè)很?chē)?yán)重的問(wèn)題。
3)ZeroMQ也支持高級(jí)消息隊(duì)列協(xié)議(AMQP),是很輕量級(jí)的消息隊(duì)列,沒(méi)有消息服務(wù)器來(lái)存儲(chǔ)和轉(zhuǎn)發(fā)消息,把側(cè)重點(diǎn)放在點(diǎn)對(duì)點(diǎn)的消息傳輸上。ZeroMQ剛推出不久,還不是很成熟,不支持消息持久化及崩潰恢復(fù),且穩(wěn)定度較差。
由于ZeroMQ是用C/C++開(kāi)發(fā),并且ZeroMQ協(xié)議格式定義得很簡(jiǎn)單,所以它的性能遠(yuǎn)遠(yuǎn)高于其他消息隊(duì)列軟件。各種消息隊(duì)列性能測(cè)評(píng)結(jié)果如圖2[8]所示。
圖2 各種消息隊(duì)列性能測(cè)評(píng)結(jié)果
從這幾種同類(lèi)軟件的比較得知,它們各有優(yōu)缺點(diǎn),我們應(yīng)該根據(jù)自己的項(xiàng)目情況,選擇合適的,揚(yáng)長(zhǎng)避短。本課題主要是要設(shè)計(jì)一個(gè)高效的分布式網(wǎng)絡(luò),對(duì)穩(wěn)定性要求不是太高,無(wú)疑,ZeroMQ是最佳選擇。
分布式系統(tǒng)由一個(gè)manager、N個(gè)客戶機(jī)和N個(gè)服務(wù)器組成,N可以是任意數(shù)量??蛻魴C(jī)和服務(wù)器都稱(chēng)作子系統(tǒng)。每個(gè)子系統(tǒng)可以隨時(shí)加入或退出系統(tǒng),并且子系統(tǒng)的加入或退出不影響其他子系統(tǒng)。在傳統(tǒng)的通訊系統(tǒng)中,客戶機(jī)向服務(wù)器發(fā)出的請(qǐng)求,以及服務(wù)器做出的回應(yīng)都會(huì)經(jīng)manager中轉(zhuǎn),這樣,隨著客戶機(jī)和服務(wù)器數(shù)量的增多,manager就會(huì)成為一個(gè)瓶頸。該系統(tǒng)摒棄了這種傳統(tǒng)模式,把manager的功能進(jìn)行了分割,manager僅保留了目錄服務(wù)的功能。例如,應(yīng)用程序X開(kāi)機(jī)后向manager注冊(cè),讓manager知道它運(yùn)行在機(jī)子Y上,應(yīng)用程序Z想發(fā)送一個(gè)消息給應(yīng)用程序X,那么它就向manager咨詢(xún)X的位置。當(dāng)manager回應(yīng)應(yīng)用程序X在機(jī)子Y上以后,Z可以直接與Y創(chuàng)建連接,并直接和Y通訊,而不用經(jīng)過(guò)manager中轉(zhuǎn)。不僅各個(gè)子系統(tǒng)能與manager通信,任何客戶機(jī)與任何服務(wù)器也能相互通信。網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)如圖3所示。
圖3 拓?fù)鋱D
ZeroMQ有現(xiàn)成的動(dòng)態(tài)鏈接庫(kù)libzmq.lib,為了實(shí)現(xiàn)我們的分布式通信網(wǎng)絡(luò),需要調(diào)用動(dòng)態(tài)鏈接庫(kù)中的API函數(shù)。Libzmq.lib中僅封裝了二十多個(gè)API函數(shù)。因?yàn)檫@些函數(shù)的某些參數(shù)的數(shù)據(jù)類(lèi)型并非基本類(lèi)型,并且如果直接調(diào)用這些函數(shù),必定會(huì)有很多代碼會(huì)被重復(fù)編寫(xiě)。為了解決這兩個(gè)問(wèn)題,對(duì)這些函數(shù)都重新進(jìn)行了封裝,
2.2.1開(kāi)發(fā)平臺(tái)
有人說(shuō)真正的程序用C,聰明的人用Delphi。因?yàn)镈elphi開(kāi)發(fā)時(shí)間短,提供了許多個(gè)可供使用的組件,很方便設(shè)計(jì)人機(jī)交互界面,功能可與C相當(dāng)。Delphi是采用面向?qū)ο蟮木幊陶Z(yǔ)言O(shè)bject Pascal,而ZeroMQ是利用C語(yǔ)言開(kāi)發(fā)的,為此,首先將原有的C動(dòng)態(tài)鏈接庫(kù)中的函數(shù)封裝成容易看懂的形式,然后再次封裝成動(dòng)態(tài)鏈接庫(kù),最后在Delphi下調(diào)用這些函數(shù),以實(shí)現(xiàn)需要的功能。
2.2.2 方案確定
1)manager對(duì)服務(wù)器的管理:manager作為目錄服務(wù)器,它要管理別的服務(wù)器,包括服務(wù)器是否在線,某服務(wù)器是提供什么服務(wù)的,服務(wù)器的綁定端口等。manager會(huì)為同一類(lèi)型的服務(wù)器創(chuàng)建一個(gè)隊(duì)列,對(duì)服務(wù)器進(jìn)行管理。為了不要讓服務(wù)器存在餓死的情況,manager利用最近最少使用算法為客戶機(jī)選擇服務(wù)器。為了知道服務(wù)器是否在線,manager與服務(wù)器之間使用心跳。即,在服務(wù)器向manager注冊(cè)后,在某個(gè)固定的時(shí)間段內(nèi)如果manager和服務(wù)器沒(méi)有收到來(lái)自對(duì)方的消息(包括心跳和連接請(qǐng)求等)則認(rèn)為對(duì)方已下線。
對(duì)于客戶端和服務(wù)器的請(qǐng)求(包括連接請(qǐng)求,心跳,服務(wù)請(qǐng)求等),manager使用單一套接字進(jìn)行處理。因?yàn)?,與使用兩個(gè)套接字分別處理客戶端和服務(wù)器請(qǐng)求相比,manager更方便管理。
2)通訊模式的選擇:ZeroMQ主要提供了請(qǐng)求回應(yīng)、發(fā)布訂閱、管道和信號(hào)4種通訊模式。其中,第4種用得比較少,主要是用來(lái)支持傳統(tǒng)的 TCP socket 模型。ZeroMQ的套接字必須配對(duì)使用,對(duì)于請(qǐng)求回應(yīng)模式有效的套接字對(duì)有:REQ and REP、 REQ and XREP 、XREQ and REP、XREQ and XREP、XREQ and XREQ、 XREP and XREP,這4種套接都既能發(fā)送消息,又能接收消息,但是REQ和REP要求收發(fā)消息,而XREQ和XREP可以異步收發(fā)消息;發(fā)布訂閱有效的套接字對(duì)是PUB and SUB,其中,PUB只能發(fā)送消息,SUB只能接收消息;管道模式的有效套接字對(duì)是PUSH and PULL,其中PUSH只能發(fā)送消息,PULL只能接收消息;信號(hào)模式的有效套接字對(duì)是PAIR and PAIR,這種模式主要用于進(jìn)程內(nèi)通信。
manager要能夠區(qū)分連接到它的不同的子系統(tǒng),才能將回應(yīng)或者心跳路由過(guò)去,所以manager端的套接字必須有路由能力,只有XREP有這個(gè)功能,所以manager使用套接字XREP實(shí)現(xiàn)通訊。
服務(wù)器與manager之間的心跳機(jī)制本身不是同步的,所以不能使用REQ或者REP,所以方案為服務(wù)器與manager的連接選擇套接字XREQ。而服務(wù)器與客戶機(jī)的通訊同樣不是單向和同步的,并且有可能有多個(gè)客戶機(jī)連接到同一個(gè)服務(wù)器,所以,此時(shí)的服務(wù)器也要有路由功能,即,只能利用套接字XREP實(shí)現(xiàn)。
與manager的通信時(shí),客戶機(jī)是發(fā)送一個(gè)消息然后接收一個(gè)回應(yīng),是同步的雙向通信,所以REQ,XREQ,XREP都可以,但是為了后續(xù)對(duì)消息的封裝容易格式統(tǒng)一,選擇XREQ實(shí)現(xiàn)。而與服務(wù)器的通訊是異步的雙向通訊,所以同樣選擇XREQ套接字來(lái)實(shí)現(xiàn)。
3)消息的封裝格式
由于manager使用單一的套接字處理客戶機(jī)和服務(wù)器發(fā)來(lái)的所有請(qǐng)求,所以這些消息除了包含消息內(nèi)容還必須封裝進(jìn)消息類(lèi)型。
客戶機(jī)發(fā)送給manager的消息封裝格式為:
Frame1:”Client”(代表客戶機(jī))
Frame2:Service name(請(qǐng)求的服務(wù)類(lèi)型)
Manager發(fā)送給客戶機(jī)的回應(yīng)消息封裝格式為:
Frame1:”Client”(代表客戶機(jī))
Frame2:Service name(請(qǐng)求的服務(wù)類(lèi)型)
Frame3:Server’s port(服務(wù)器端口號(hào))
服務(wù)器發(fā)送給manager的注冊(cè)信息:
Frame1:”Worker”(代表服務(wù)器)
Frame2:”READY”(表示服務(wù)器已準(zhǔn)備好)
Fream3:Service name(提供的服務(wù)類(lèi)型)
服務(wù)器與manager間發(fā)送的心跳:
Frame1:”Worker”(代表服務(wù)器)
Frame2:“HEARTBEAT”(心跳)
manager感知整個(gè)系統(tǒng)的拓?fù)洹W酉到y(tǒng)開(kāi)機(jī)后,首先連接上manager,接著發(fā)送一個(gè)消息給manager(客戶機(jī)發(fā)送請(qǐng)求的服務(wù)類(lèi)型;服務(wù)器發(fā)送自身的名稱(chēng)、IP地址及提供的服務(wù)類(lèi)型)。manager根據(jù)消息類(lèi)型判斷是來(lái)自客戶機(jī)還是服務(wù)器,如果來(lái)自服務(wù)器,并且控制命令是”READY”,則根據(jù)service name信息判斷是否已經(jīng)存在這項(xiàng)服務(wù)的隊(duì)列,如果不存在則創(chuàng)建一個(gè)新的隊(duì)列,如果存在則把此服務(wù)器信息添加到這個(gè)隊(duì)列最后;如果控制命令是“HEATER”,則重置此服務(wù)器的心跳截止時(shí)間。若來(lái)自客戶機(jī),則查找是否存在客戶機(jī)請(qǐng)求的服務(wù)類(lèi)型對(duì)應(yīng)的服務(wù)器,若存在則從服務(wù)隊(duì)列中取出對(duì)列首的服務(wù)器的端口信息發(fā)送給客戶機(jī),并將該服務(wù)器放到隊(duì)列末尾;否則回復(fù)服務(wù)器不存在的消息,如“sorry!”。manager同時(shí)利用心跳機(jī)制監(jiān)測(cè)服務(wù)器的在線信息,如果發(fā)現(xiàn)服務(wù)器下線,則從服務(wù)隊(duì)列中將該服務(wù)器刪除。程序流程的粗略框架如圖4所示。
圖4 manager處理流程圖
服務(wù)器向manager注冊(cè)后,等待客戶機(jī)連接,直接與客戶機(jī)通訊,并定時(shí)向manager發(fā)送heartbeat信息。服務(wù)器的程序流程粗略框架如圖5所示。
客戶機(jī)向服務(wù)器請(qǐng)求前,首先連接到manager,向manager咨詢(xún)是否有提供某項(xiàng)服務(wù)的服務(wù)器存在,如果manager返回服務(wù)器的端口號(hào),則客戶機(jī)連接到服務(wù)器,直接向服務(wù)器 請(qǐng)求數(shù)據(jù);如果manager返回的是“sorry!”,則客戶機(jī)等待一段時(shí)間再重新連接??蛻魴C(jī)的程序流程的粗略框架如圖6所示。
圖6 客戶機(jī)處理流程圖
為了測(cè)試ZeroMQ的性能,在兩臺(tái)電腦之間發(fā)送數(shù)據(jù)10000000條消息,接收只用了不到0.2 μs。說(shuō)以,實(shí)驗(yàn)證實(shí)了ZeroMQ的高效性。測(cè)試結(jié)果如圖7所示。
圖7 測(cè)試結(jié)果
這個(gè)系統(tǒng)已經(jīng)用于輪軌檢測(cè)的試驗(yàn)中。由于,檢測(cè)的時(shí)間長(zhǎng),并且檢測(cè)點(diǎn)多等特點(diǎn),短時(shí)間采集到大量數(shù)據(jù),采集卡的存儲(chǔ)空間遠(yuǎn)遠(yuǎn)不夠,所以,如何及時(shí)把數(shù)據(jù)轉(zhuǎn)運(yùn)走就是一個(gè)很關(guān)鍵的問(wèn)題?;赯eroMQ通訊系統(tǒng)的交互面向消息,并使用消息分批發(fā)送,大大提高了傳輸效率,從而有效地解決了數(shù)據(jù)存儲(chǔ)難的問(wèn)題。
本系統(tǒng)是一個(gè)基于ZeroMQ小型的分布式系統(tǒng)。ZeroMQ的消息傳送機(jī)制大大提高了傳輸效率,并且它的接口函數(shù)簡(jiǎn)單容易上手。系統(tǒng)中使用的平臺(tái)是Delphi2007,它提供了許多個(gè)可供使用的構(gòu)件,方便開(kāi)發(fā)人機(jī)交互界面。實(shí)踐證明本系統(tǒng)能實(shí)現(xiàn)高效的數(shù)據(jù)傳輸。然而,本系統(tǒng)還存在一個(gè)缺點(diǎn):如果manager出現(xiàn)問(wèn)題,整個(gè)系統(tǒng)就會(huì)崩潰掉。這個(gè)問(wèn)題可以根據(jù)實(shí)際情況通過(guò)增加一個(gè)備用manager來(lái)解決。ZeroMQ剛推出不久,國(guó)內(nèi)外的應(yīng)用還比較少,主要集中在web應(yīng)用上,但因其較同類(lèi)軟件具有顯著優(yōu)勢(shì),越來(lái)越受到大家的青睞。同時(shí),ZeroMQ還存在不支持消息持久化和崩潰恢復(fù)等問(wèn)題。ZeroMQ還在不斷完善中,希望這些問(wèn)題在以后都能得到很好的解決。
[1]溫情月朗.分布式系統(tǒng)介紹[EB/OL].http://qa.taobao.com/?p=3527,2009.
[2]SOSO百科.分布式系統(tǒng)[EB/OL].http://baike.soso.com/v5697460.htm.
[4]program_think.開(kāi)源點(diǎn)評(píng):ZeroMQ簡(jiǎn)介[EB/OL].http://blog.csdn.net/program_think/article/details/6687076,2011.
[5]鄒永斌.Introduction to Message Oriented Middleware[EB/OL].http://wenku.baidu.com/view/3ba1a73710661ed9ad51f394.html,2011.
[6]Dccmx.史上最快消息內(nèi)核—ZeroMQ[EB/OL].http://itindex.net/detail/4067-%E6%B6%88%E6%81%AF-%E5%86%85%E6%A0%B8-zeromq,2011.
[7]Julien.ActiveMQ or RabbitMQ or ZeroMQ or ActiveMQ[EB/OL].http://stackoverflow.com/questions/731233/activemq-or-rabbitmq-orzeromq-or,2009.
[8]SZSM.測(cè)試比較:消息隊(duì)列軟件產(chǎn)品大比拼