首頁>技術>

1、概述

從本文開始,我們介紹另一型別的系統間通訊及輸:MQ訊息佇列。首先我們將討論幾種常用訊息佇列協議的基本原理和工作方式,包括MQTT、XMPP、Stomp、AMQP、OpenWire等。然後在這個基礎上介紹兩款MQ產品:ActiveMQ和RabbitMQ,它們是現在業務系統中應用廣泛的訊息佇列軟體。包括他們的安裝、執行、支援協議、叢集化和呼叫方式。

2、基本概念

2-1、訊息

首先有三個基本概念在開篇前我們需要進行討論:訊息、訊息協議、訊息佇列。訊息既是資訊的載體 這個描述相信各位讀者都能夠明白。為了讓訊息傳送者和訊息接收者都能夠明白訊息所承載的資訊(訊息傳送者需要知道如何構造訊息;訊息接收者需要知道如何解析訊息),它們就需要按照一種統一的格式描述訊息,這種統一的格式稱之為訊息協議。所以,有效的訊息一定具有某一種格式;而沒有格式的訊息是沒有意義的。

而訊息從傳送者到接收者的方式也有兩種。一種我們可以稱為即時訊息通訊,也就是說訊息從一端發出後(訊息傳送者)立即就可以達到另一端(訊息接收者),這種方式的具體實現就是我們已經介紹過的RPC(當然單純的http通訊也滿足這個定義);另一種方式稱為延遲訊息通訊,即訊息從某一端發出後,首先進入一個容器進行臨時儲存,當達到某種條件後,再由這個容器傳送給另一端。 這個容器的一種具體實現就是訊息佇列。

2-2、知識結構

訊息佇列和已經介紹過的RPC相同的是:無論是RPC也好,訊息佇列也好他們都建立在網路IO模型基礎上(我們已經介紹過多種網路IO模型)。先進的網路IO模型將賦予MQ協議優異的效能表現(當然,效能也不僅僅取決於網路IO模型)。

從上圖可以看到,某一種訊息通訊軟體(或者叫做程式庫)的實現都建立在“協議”基礎上:RMI程式庫建立在RMI協議上(RMI協議是JAVA規範協議的一部分) ,屬於一種“即時訊息通訊”;RabbitMQ和Qpid訊息通訊軟體的設計依據是AMQP協議,屬於一種“延遲訊息通訊”。

雖然訊息協議存在“私有協議”和“開放協議”之分(是否向行業開放訊息規範文件、是否允許某個組織更改協議),雖然某一個軟體(程式庫)不一定只支援一種協議(例如ActiveMQ實現了多種訊息協議),雖然某一種協議也不一定只有一種軟體(程式庫)實現(例如能夠支援webservice協議的程式庫就有Codehaus XFire、Apache CXF、Jboss RESTEasy等),但是這並不影響“某一種訊息通訊軟體(或者叫做程式庫)的實現都建立在“協議”基礎上”的概念,反而是這個基本概念加強了。

3、訊息協議

3-1、XMPP協議

3-1-1、定義

XMPP is the Extensible Messaging and Presence Protocol, a set of open technologies for instant messaging, presence, multi-party chat, voice and video calls, collaboration, lightweight middleware, content syndication, and generalized routing of XML data.

以上內容引用自XMPP官網,這個定義已經可以清楚表明XMPP協議的用途和特性。XMPP的前身是Jabber,一個開源形式組織制定的網路即時通訊協議。XMPP目前被IETF國際標準組織完成了標準化工作。

XMPP基於XML,用於IM系統的開發。國內比較流行的XMPP伺服器叫做Openfire,它使用MINA作為下層的網路IO框架(不是MINA2是MINA1);國外用的比較多的XMPP伺服器叫做Tigase,它的官網號稱單節點可以支撐50萬用戶線上,叢集可以支援100萬用戶線上:(http://projects.tigase.org/)

Cluster with over 1mn online users . 500k online users on a single machine

當然如果讀者所在公司需要開發IM系統,除了使用現成的XMPP伺服器以外,還需要實現了XMPP協議的客戶端或者開發包(以便進行擴充套件開發)。您可以在XMPP官網檢視到XMPP官方推薦的開發包,各種語言的支援基本上都有:http://xmpp.org/software/libraries.html

筆者曾參與過某幾款IM系統的開發(包括自己創業的專案),總的來說XMPP協議本身是不錯的選擇,但是學習起來會耗費相當的時間,並且某些XMPP客戶端、伺服器端或者程式庫並沒有這些開發團隊宣傳的那麼穩定好用。所以如果您的公司需要進行IM系統的開發,那麼創立私有的訊息協議也會是一個不錯的選擇。

3-1-2、協議通訊過程示例

為了讓各位讀者對XMPP協議有一個感性認識,這裡我們給出一個XMPP協議處理“IM使用者登入”操作的過程(XMPP的登入方式分為有使用者密碼和無使用者密碼兩種方式,這裡我們介紹無密碼登入方式)。

透過上圖可以看到,XMPP協議中的xml片段。這裡出現了幾個XMPP協議中的關鍵資訊,例如:

stream標記:通訊流標記,是指XMPP的客戶端或者伺服器端向對方發起的通訊請求(或者響應)。通訊流並不攜帶正真的內容資訊,指示表明客戶端和伺服器端發生了一次互動。stream的屬性包括:to、from、id、xml:lang、version等。

iq標記:iq標記是Info/Query的簡稱(你可以理解成查詢資訊請求),一般是一組的形式出現,由客戶端發起查詢請求,由伺服器端返回查詢結果。由於查詢請求的型別不一樣,iq標記中可以嵌入的子標記就有很多。例如,可以嵌入bind標記,表明某個使用者和jid的繫結關係;可以嵌入多個item標記,表明查詢得到的這個使用者的好友資訊(如下)。

<iq to='[email protected]/someresource' type='result' id='roster'>

<query xmlns='jabber:iq:roster'>

<item jid='[email protected]' name='someone1'/>

<item jid='[email protected]' name='someone2'/>

</query>

</iq>

jid標記:jid(JabberID)是XMPP協議中標示,它用來標示XMPP網路中的各個XMPP實體(實體可以是某一個使用者、某一個伺服器、某一個聊天室),規範格式如下:

jid = [ node "@" ] domain [ "/" resource ]

1

還有未出現的message、presence標記:message是實體內容標記,記錄了聊天的真實內容;presence標記表示了XMPP使用者的服務狀態(離線,線上、忙碌等)。示例如下:

<message to="[email protected]/someresource" type="chat">

<body>helloword。。。</body>

</message>

3-2、Stomp協議

3-2-1、定義

Stomp協議,英文全名Streaming Text Orientated Message Protocol,中文名稱為 ‘流文字定向訊息協議’。是一種以純文字為載體的協議(以文字為載體的意思是它的訊息格式規範中沒有類似XMPP協議那樣的xml格式要求,你可以將它看作‘半結構化資料’)。目前Stomp協議有兩個版本:V1.1和V1.2。

一個標準的Stomp協議包括以下部分:命令/資訊關鍵字、頭資訊、文字內容。如下圖所示:

以下為一段簡單的協議資訊示例:

CONNECT

accept-version:1.2

someparam1:value1

someparam2:value2

this is conntecon ^@

上面的示例中,我們使用了Stomp協議的CONNECT命令,它的意思為連線到Stomp代理端,並且攜帶了要求代理端的版本資訊和兩個自定義的K-V資訊(請注意’^@’符號,STOMP協議中用它來表示NULL)。

Stomp協議中有兩個重要的角色:STOMP客戶端與任意STOMP訊息代理(Broker)。如下圖所示:

由於Stomp協議的結構如此簡單,以至於任何理解Stomp協議命令格式的技術人員都可以開發Stomp的代理端或者Stomp的客戶端,並將自己滿足Stomp協議的系統輕鬆接入另一個同樣滿足Stomp協議的第三方系統(例如activeMQ)。

3-2-2、基本命令/返回資訊

和介紹XMPP協議的方式類似,為了讓讀者對Stomp協議有進一步的認識,本小節我們介紹Stomp協議的基本命令和代理端返回的資訊種類,並且列舉一些例項進行使用講解。

在Stomp協議中,主要有以下命令/返回資訊(有的文章中也稱一個完整的資訊為幀)。這些命令/返回資訊構成了Stomp協議的主體,並能夠支援您的Stomp客戶端和Stomp代理端完成連線、傳送、訂閱、事務、響應的整個操作過程。這些命令/返回是:

CONNECT/STOMP命令: 客戶端透過使用CONNECT命令,連線到Stomp代理端。如果使用STOMP命令,那麼Stomp代理端的版本必須是1.2。

CONNECTED資訊:當Stomp代理端收到客戶端傳送來的Connect命令並且處理成功後,將向這個客戶端返回CONNECTED狀態資訊;如果這個過程中出現任何問題,還可能返回ERROR資訊

SEND 傳送命令:客戶端使用SEND命令,向某個指定位置(代理端上的一個虛擬路徑)傳送內容。這樣在這個路徑上訂閱了訊息事件的其它客戶端,將能夠收到這個訊息。

SUBSCRIBE 訂閱命令:客戶端使用SUBSCRIBE訂閱命令,向Stomp服務代理訂閱某一個虛擬路徑上的監聽。這樣當其它客戶端使用SEND命令傳送內容到這個路徑上時,這個客戶端就可以收到這個訊息。在使用SUBSCRIBE時,有一個重要的ACK屬性。這個ACK屬性說明了Stomp服務代理端傳送給這個客戶端的訊息是否需要收到一個ACK命令,才認為這個訊息處理成功了。如下所示:

SUBSCRIBE

id:XXXXXXXXX

destination:/test

ack:client

^@

以上SUBSCRIBE命令資訊說明,客戶端訂閱的虛擬位置是test。且命令資訊中ack屬性為client,說明當客戶端收到訊息時,必須向代理端傳送ack命令,代理端才認為這個訊息處理成功了(ack的值只有三種:auto(預設)、client和client-individual)。

UNSUBSCRIBE 退訂命令:客戶端使用這個命令,取消對某個路徑上訊息事件的監聽。如果客戶端給出的路徑之前就沒有被這個客戶端訂閱,那麼這個命令執行無效。

MESSAGE 資訊:當客戶端在某個訂閱的位置收到訊息時,這個訊息將透過MESSAGE關鍵字進行描述。類似以下資訊就是從代理端拿到的訊息描述:

MESSAGE

redelivered:true

message-id:ID:localhost-34450-1457321490460-4:24:-1:1:1

destination:/test

timestamp:1457331607873

expires:0

priority:4

BEGIN 開始事務命令: Stomp協議支援事務模式,在這種模式下,使用Send命令從某個客戶端發出的訊息,在沒有使用COMMIT正式提交前,這些訊息是不會真正傳送給Stomp代理端的。BEGIN命令就是用於開啟事務。注意,一個事務中可以有一條訊息,也可以有多條訊息。

COMMIT 提交命令: 當完成事務中的資訊定義後,使用該命令提交事務。只有使用COMMIT命令後,在某一個事務中的一條或者多條訊息才會進入Stomp代理端的佇列(訂閱了事件的其它客戶端才能收到這些訊息)。

ABORT 取消/終止事務命令:很明顯,這個命令用於取消/終止當前還沒有執行COMMIT命令的事務。

ACK 確認命令:當客戶端使用SUBSCRIBE命令進行訂閱時,如果在SUBSCRIBE命令中制定ack屬性為client,那麼這個客戶端在收到某條訊息(id為XXXX)後,必須向Stomp代理端傳送ACK命令,這樣代理端才會認為訊息處理成功了;如果Stomp客戶端在斷開連線之前都沒有傳送ACK命令,那麼Stomp代理端將在這個客戶端斷開連線後,將這條訊息傳送給其它客戶端。

ACK

id:MESSAGE ID

^@

請注意head部分的id屬性,傳遞的id屬性是之前收到的MESSAGE資訊的id標示。

NACK 不確認命令:同樣是以上的SUBSCRIBE命令的狀態下,如果這時Stomp客戶端向Stomp代理端傳送NACK資訊,證明這條訊息在這個客戶端處理失敗。Stomp代理端將會把這條訊息傳送給另一個客戶端(無論當前的客戶端是否斷開連線)。

DISCONNECT 斷開命令:這個命令將斷開Stomp客戶端與Stomp代理端的連線。

(接下文)

12
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 直播APP原始碼開發,直播APP原始碼搭建,如何最佳化程式?