第201期 / July 5, 2014

研發新視界

分享到臉書!分享到維特!分享到噗浪!分享到Google+!分享到微博!轉寄友人友善列印

快速且高效能的分散式非同步通訊函式庫-ZMQ

作者/鄭子豪

[發表日期:2014/7/4]

前言

分散式的大型資訊系統開發的過程中,不同節點間的資料傳送方式需要非常謹慎地選擇,當我們接收到一系列的輸入時,訊息佇列(Message Queue)服務提供了非同步的通信協議,將資料排列至佇列中,分別記錄發生時間、輸入裝置種類、特定參數等,待接收者從佇列取用。Message Queue允許接收者在消息發送後過一段時間再取回消息,不需要即刻回應,有別於HTTP等同步協議,HTTP客戶端在發出請求後必須等待伺服器回應。某些情況下我們需要非同步的通信協議,如期貨選擇權交易系統中的委託下單程式,經過風險控管程式以後,委託訂單電文即送給負責搓合訂單的系統等待進行訂單搓合。相反地,Message Queue非同步的特性也造成了一個缺點,就是接收者必須輪流詢問消息佇列,才能收到最近的消息,因此通常會在接收端設計一個回報機制,已確認電文是否完整送達。針對需要允許非同步的訊息傳達和交換方式的各種系統,訊息佇列服務是非常重要的元素,常見的訊息佇列服務如ActiveMQ、RabbitMQ等。Message Queue 由以下三者構成:
  • Client node :發送需求的程式,可能來自其他硬體設備。

  • Process :實際處理需求的程式。

  • Message broker (Job Server) :執行 Message Queue 服務與process,辨認Client需要何種服務後分配給一直循環等候的process。


《圖一》Message Queue示意圖


Client 發送出需求之後,會將要需要的資料及動作記錄在 Message broker上, Message broker 會查看是否有空閒並且符合需求的 Worker,若 Worker 有空, Message broker 就會從佇列中把 Client 的需求轉移給 Worker 執行。 Worker 結束工作後,會發送通知給Message broker,這時 Message broker 就會視狀況把結果回傳給 Client 。這樣的機制讓 Client 不必再等候需求的執行結果,而可以直接再往下執行其他動作。

有別於一般的Message Queue,由iMatix公司和大量貢獻者組成的社群共同開發的ZMQ提供了系統開發者一個開發更方便、傳輸效率更高的選擇,支援port間多對多連接且不需要消息代理(message broker)。以往為了讓所有節點彼此有辦法進行溝通,常讓所有節點都連向中間的訊息交換伺服器(即broker),節點之間若需連接一律透過broker進行,在此架構下各節點只需要在意訊息的種類和內容即可,但從預防連線失效的角度而言,此架構下過度依賴broker,若broker失效則所有節點均無法正常運行;當節點數增加時broker的負荷量也會同步的增加。

相較之下ZMQ少了message broker,對於注重擴展性及穩定性的架構是相對較佳的選擇。ZMQ對於一般熱門的程式語言如C / C++ / Java / .NET / Python / PHP等均有對應的封裝,方便客戶端或服務端進行開發。ZMQ甚至可套用到許多的平行演算流程中達到分散式運算的目的,由一台電腦產生需要運算的參數,多台電腦分別接收這些需要運算的參數同時執行數值運算,將結果匯回主電腦執行,再產生下一階段演算所需的參數並重複以上過程,就可以避免將許多運算集中在同一台電腦而讓運算速度變慢的問題。

與Message queue相比,ZMQ還有處理速度的優勢,Mike Hadlow曾對此進行實驗,針對ZMQ與三種message queue的傳輸效率,分別為MSMQ、ActiveMQ、RabbitMQ,每個queue被要求送出、接收一百萬筆訊息,下圖表示每秒傳輸訊息量,非broker架構的ZMQ測試的結果相當驚人,接收量為MSMQ與ActiveMQ的十倍以上;傳送量更為其他任一者的19倍以上。



有別於傳統socket的運作邏輯

ZMQ與一般傳統所使用的Connection-oriented socket不同,不須考量連線順序之問題。如以下簡單演算法所示,在ZMQ的架構下使用被ZMQ所支援的TCP通訊方式進行交談,Algorithm 1(REQUEST)負責產生三組亂數,產生後將其輸出至銀幕,接著將兩組數字視同request傳送至Algorithm 2(REPLY);Algorithm 2(REPLY)則先印出process ID,再將接收到的數字進行加總運算,運算後將答案回傳給Algorithm 1(REQUEST)。執行時首先執行三組Algorithm 2(REPLY),再執行一組Algorithm 1(REQUEST),於是Algorithm 1(REQUEST)便能與另外三組Algorithm 2(REPLY)進行交談。


《圖二》


以下為預期結果輸出,REQUEST執行一次,輸出自己產生的所有數字以後,再把從REPLY接收到的計算結果輸出;而三組REPLY的輸出各自先印出所屬process ID,接著將各自進行的動作內容印出,歸功於ZMQ的”無關連線先後順序”的特性,此例中我們不需要建立三組REQUEST及三組REPLY,透過一對多的架構讓單一的REQUEST即可滿足我們的需求。


《圖三》


自動負載平衡

由以上輸出可得知,REQUEST依序分配給三個REPLY,REQUEST端會將sent的message用Round-robin的方式分給所有的遠端連線,因此對於所有的連線ZMQ均會依照此規則平均分配工作。但因為先前有提到自動連線,因此會有個問題,當第一個連線接上時,其它連線還來不及連上,此時request可能已經大量分配給第一個連上的,為了解決這問題,需加入time.sleep()來等所有worker連上線避免行程飢餓。

支援多種消息傳遞機制

前段演示以TCP實作連線的邏輯,ZMQ除了有能力提供多個socket連到一個socket的架構且不受連線先後順序影響外,同時也支援行程間通訊(IPC與Inproc)以及廣播(multicast)等,讓通訊效率最佳化,ZMQ甚至提供了基於UDP的廣播通訊方式供使用者節省傳輸的封包。

跨平台跨語言溝通

良好的跨平台性,支援多種OS,如Linux/Windows/OS X等,大型系統的前台、中台、與後台的硬體設備常常會安裝不同的作業系統,使用ZMQ進行溝通對於系統開發者而言可以省去對於作業系統選擇的煩惱,方便跨部門合作。ZMQ也支援Basic、C、C#、C++、delphi、Haskell、Java、JavaScript、PHP、Python、Ruby等語言,對於熟悉不同語言的工程師來說是相當有易用性的。

支援多種組合架構模式

ZMQ支援多種架構模式,以下三者為例:

一、請求響應(Request-Reply)架構

將一組客戶端連接到一組伺服器,針對遠程過程調用和任務分發模式。以金融業的期貨選擇權交易系統為例,電文之間的傳送即使用此架構進行,避免連線過程中的資訊流失。


《圖四》Request-Reply架構的ZMQ


期貨選擇權的風險管理系統連接期貨商與交易所,下單時將有多位交易員與下單程式進行下單,將委託資料送至風管系統的threads,在同一時間內系統中的數個thread必須同時應付所有來自客戶端的下單委託電文,此時ZMQ即扮演非常重要的角色。ZMQ的socket之間可以多個互相連線,一個socket可能有N個節點連接,同一個socket也可以連結在不同的位址上,因此不同的用戶端得以與相同的thread進行連接。此外,透過ZMQ風控系統可以達到multithreading的目的,將委託電文置入隊列中等待進一步送至交易所進行不同訂單的交易媒合,因為訂單數量非常龐大,在極短時間內,ZMQ透過Request-Reply架構,同時用不同的thread接收大量的委託資料,並傳回回報通知;相對地,回報通知也反向利用ZMQ將委託成功/失敗通知回傳給各個Client。系統內部的許多不同目的的thread也因為資料量龐大且需要逐筆進行預算,透過ZMQ的Request-Repl架構來完成溝通。以上的例子實作了單一伺服器內不同thread之間的溝通以及不同機器之間的溝通,相較於一般message queue僅支援相同機器內部溝通,開發大型系統若使用ZMQ將能降低複雜度,同時解決跨設備、設備內部的溝通問題。

二、發布訂閱(Publish-Submit)架構

將一組發布者連接到一組訂閱者,為一種數據分發模式。此模式又稱觀察者模式,所有PUB發送的消息會廣播給所有SUB的連線,速度較Request-Reply快,在期貨選擇權風險控管系統中,適合針對接收行情的thread應用。以期貨選擇權交易風險控管系統為例,每日接收的行情資料數量相當龐大,每數秒鐘還需要重新下載一次,風控系統能利用ZMQ的Publish-Subscribe架構,將來源資料發布給所有Client。


《圖五》Publish-Subscribe架構的ZMQ


三、推拉模式(Push-Pull)架構

當我們想將資料往某個方向負載平衡地推送時,能透過Push-Pull架構來實作,PUSH會將負載分散給PULL端,而且只能由PUSH推往PULL端。


《圖六》Push-Pull架構的ZMQ


四、Inproc

Inproc由in-process兩字組成,讓執行續能透過記憶體直接進行訊息交換,速度較TCP與ICP為快。使用此模式時需指定 [transport ://endpoint,transport ]指定底層傳輸協議,使用inproc時應指定為inproc;endpoint為端點名稱,connects 與 binds會同時進行,並能保證送達,範例如下:


《圖七》


ZMQ的其他優點

1.協議較TCP更快、適用於大型叢集和分佈式計算
2.提供非同步I/O模式,適用於可擴展的多核應用開發
3.開發者社團提供技術支援,發展迅速
4.擁有iMatix公司的商業級別支援,卻完全免費
5.連線先後順序無關且具自動重連機制
6.多個Socket連線、多位址連結
7.自動負載平衡

總結

由ZMQ開發包中已經包含了非常豐富的C語言的使用範例可知,ZMQ的背後開發者社團相當注重開發難易度的考量,希望將各種系統的開重心置於核心演算法與核心功能,而開發出了更小、更快、更簡單的智慧傳輸協議類別庫,盡管名字中含有MQ(message Queue),ZMQ實為傳輸層的API,靠著點對點無中間節點、強調消息收發模式、以統一介面支援多種底層通信方式及非同步、強調性能的特色,給予系統工程師新的開發體驗。一般含有 Broker的Message Queue,有個中控中心可確保所有的訊息能夠保留起來,對於收發中心有需求的系統開發者可以考慮,ZMQ則未實作收發中心,但對於大量的訊息傳輸相當有效率,且連線失效時同樣會暫存封包。

雲端運算的架構下常有降低耦合的需求,為了在鬆綁前台、中台與後台之間的邏輯關聯的同時又能擴充運算能力與硬體設備,系統開發者們除了傳統的Message queue外,可選擇ZMQ來實作雲端服務間訊息交換與遞送技術,如工研院的[Smart Home Group]雲端服務整合軟體架構設計專案與Salt便使用ZMQ來進行,達到增加系統彈性的目的,提供完善的(SaaS)Software as a Service、(PaaS)Platform as a Service與(IaaS)Infrastructure as a Service服務。

(本文轉載自2014/6/6發表之RUN!PC文章)

參考資料

1.ZMQAPI.
2.雲端服務與經驗談 [2] 雲端服務與架構演化.[2013-03-25]
3.有關Salt雲端管理要知道的5件事.[2013-09-16]
4.新世紀通訊函式庫-ZeroMQ.[2011-11-31]
5.Message Queue Shootout![2011-04-10]
6.Middleware Trends And Market Leaders 2011.[2013-06-08].
7.ZeroMQ Message Transfer Protocol.[2013-06-08].
8.GitHub Search: ZMTP.[2013-06-08].
9.iMatix will end OpenAMQ support by 2011. openamq-dev maillist.[14 July 2012].
10.What is wrong with AMQP (and how to fix it). iMatix Corporation.[14 July 2012].
11.ZeroMQ and Crossroads I/O: Forking over trademarks.LWN.net.[14 July 2012].
12.NetMQ. GitHub.[23 May 2013].