轉 https://www.ibm.com/developerworks/cn/opensource/os-cn-qpid1/
https://www.ibm.com/developerworks/cn/opensource/os-cn-qpid2/
Qpid 是 Apache 開發的一款面向對象的消息中間件,它是一個 AMQP 的實現,可以和其他符合 AMQP 協議的系統進行通信。Qpid 提供了 C++/Python/Java/C# 等主流編程語言的客戶端庫,安裝使用非常方便。相對於其他的 AMQP 實現,Qpid 社區十分活躍,有望成爲標準 AMQP 中間件產品。除了符合 AMQP 基本要求之外,Qpid 提供了很多額外的 HA 特性,非常適於集羣環境下的消息通信。
引子,Qpid 使用場景
通信是一個基本的需求,正如人與人之間需要交流一樣,比較大型的軟件系統也往往需要內部或者外部通信。
在系統間通信最基礎的通信方式是 socket,但 socket 比較底層。使用起來非常不易。如果需要一些高級特性,需要很多的編程負擔。
與 socket 的原始對應,企業級的應用軟件往往有着各種各樣從簡單到複雜的通信需求,表現爲不同的通信模型。常見的有:
- 點對點:A 發消息給 B。
- 廣播:A 發給所有其他人的消息
- 組播:A 發給多個但不是所有其他人的消息。
- Requester/response:類似訪問網頁的通信方式,客戶端發請求並等待,服務端回覆該請求
- Pub-sub:類似雜誌發行,出版雜誌的人並不知道誰在看這本雜誌,訂閱的人並不關心誰在發表這本雜誌。出版的人只管將信息發佈出去,訂閱的人也只在需要的時候收到該信息。
- Store-and-forward:存儲轉發模型類似信件投遞,寫信的人將消息寫給某人,但在將信件發出的時候,收信的人並不一定在家等待,也並不知道有消息給他。但這個消息不會丟失,會放在收信者的信箱中。這種模型允許信息的異步交換。
- 其他通信模型。。。
除了各類不同的通信模型之外,系統間的通信還有其他一些需要考慮的問題。比如企業級應用往往有巨量的數據需要交換,對可靠性的要求也比較高。比如一個分佈式的財務處理軟件,每時每刻都有成千上萬的用戶在使用,需要產生難以想象的海量消息,每個消息可能都關乎某人的銀行賬戶等關鍵信息,如果丟失將帶來巨大損失。編寫這樣一個通信中間件不是一件容易的事情,即使編寫出來,假如需要和其他的軟件系統交互信息,又需要大量的格式轉換,接口遷移等工作。
爲了解決以上這些問題,人們開發出了很多的軟件產品和協議。從早期的 RPC,到複雜的面向消息的中間件 (MOM),再到 JMS,人們取得了很多的進步,但是這些技術還是存在各自的問題。
RPC,Corba 等技術是同步的,即調用者必須等待對方的回覆,這意味着調用者必須瞭解接收者,是一種緊耦合的模型。緊耦合意味着不靈活,而在軟件行業唯一不變的就是變化,當需求和環境發生變化時,緊耦合的應用修改代價非常高。
爲此衆多的消息中間件產品應運而生,打破了消息生產者和消費者之間的緊耦合關係。但中間件產品是由各個廠商自行定義和實現的,在整合企業級應用的時候,人們發現各種應用往往採用了不同的技術和中間件產品,要想讓這些產品互通消息,又是一件非常困難的事情。
JMS 是標準化的一種努力,但其缺點在於 JMS 是 J2EE 的標準,假如不是採用 Java 技術實現的產品,想使用 JMS 還是比較麻煩的。
因此即便到了今天人們還是希望有一款功能強大,平臺 / 語言無關,標準化的面向消息的中間件產品。
假如這正是您時時刻刻所想的問題,那麼 Qpid 便是您值得了解的一款開源軟件。它實現了可靠複雜的通信中間件,支持多種通信模型,效率高,平臺語言無關,而且實現了業界的通信標準 AMQP。
AMQP 和 Qpid
AMQP 是 Advanced Message Queuing Protocol,即高級消息隊列協議。和前面羅列的技術不同,AMQP 是一個標準化的消息中間件協議。她的理想是讓不同語言,不同系統的應用互相通信,並提供一個簡單統一的模型和編程接口。這樣,人們就可以採用各種語言和平臺來實現自己的應用,當需要和其他系統通信時,只要承認 AMQP 協議即可。
舉個不太自然的例子吧。。。
世界各地的人們由於地理和歷史的原因,使用着各種不同的語言,相互交流十分不易。AMQP 類似一架自動翻譯機,當我用中文對它說了什麼之後,假如一個英語世界的人想聽的話,可以聽到 英文版的 精確的一字不差的翻譯。
此外這個翻譯機還提供其他很多好處,比如中國和美國有 12 小時的時差,假如我現在希望和某個美國人通話,他必須半夜爬起來,或者我必須等到他起牀,但通過這臺機器,我說完就行了,那個美國人起牀後就會聽到的。我很放心,這句話絕不會丟掉,也絕不會走樣;
我其實可以不關心有多少人來聽,假如有更多的人都想聽,那麼他們也可以隨時聽到。
假如我只想讓部分人聽到,還可以加密認證;
假如有些人不想聽,有些人想聽,那麼這臺翻譯機也能知道誰想聽,而不會將我的聲音發給不想聽到的人。
這種交流方式和體驗,作爲一個人類我還不曾享受過,但是 AMQP 已經爲 衆多的計算機軟件提供了這種服務。
AMQP 來自 JPMorgon,最初只是這個財大氣粗的投行內部使用的消息中間件。發起人 John O'Hara 很有氣魄,他說“從 1996 年開始到 2003 我一直在等這樣一個標準,但始終沒有等到,我已經等不下去了”,並且“投行對這類標準的需求最迫切,而銀行又從來不缺乏技術專家” ,所以他自己開發了一個。我想一個人如果想成就什麼事,就需要這樣的英雄氣概吧。
因爲他的努力,AMQP 從金融界迅速推廣到整個計算機行業,參與者包括了很多 IT 巨頭。雖然今天 AMQP 依舊是一個草案,但值得我們拭目以待。
AMQP 的基本構架如下:
圖 1. AMQP 系統構架
在 AMQP 模型中,消息的 producer 將 Message 發送給 Exchange,Exchange 負責交換 / 路由,將消息正確地轉發給相應的 Queue。消息的 Consumer 從 Queue 中讀取消息。
這個過程是異步的,Producer 和 Consumer 沒有直接聯繫甚至可以不知道彼此的存在。
Exchange 如何進行路由的呢?
這便依靠 Routing Key,每個消息都有一個 routing Key,而每個 Queue 都可以通過一個 Binding 將自己所感興趣的 Routing Key 告訴 Exchange,這樣 Exchange 便可以將消息正確地轉發給相應的 Queue。下表列出了這幾個關鍵概念的定義。
表 1. AMQP 的幾個概念
概念 | 描述 |
---|---|
Producer | A program that writes messages to an Exchange. To do this, the program creates a message, fills the message with content, gives the message a Routing Key, and sends the message to an Exchange. |
Routing Key | A string that the Exchangecan use to determine to which Queuesthe message should be delivered. |
Exchange | Accepts messages from Producersand routes them to Queuesif the message meets the criteria expressed in a binding. |
Binding | Defines the relationship between an Exchangeand a Queue, specifying which messages should be routed to a given Queue |
Queue | Holds messages and delivers them to the Consumersthat subscribe to the Queue. |
Consumer | A program that reads messages from a Queue. A Consumercan create, subscribe to, share, use, or destroy Queueand their Bindings(as long as it has have permission to do so). |
爲了支持各種常見的通信模型,AMQP 定義了不同的 Exchange 類型,如下表所示 :
表 2. AMQP 定義的 Exchange 類型
Exchange 類型 | 路由行爲 |
---|---|
Fan-Out | Messages are routed to every Queue bound to the Exchange, ignoring the Routing Key |
Direct | A message is routed only if a Queue'sBinding Keyis the same as the message's Routing Key |
Topic | Similar to a Direct Exchange, but it supports multipart keys that contain multiple words separated by the "." delimiter; for instance, a message Producer can create messages with Routing Keys like usa.news, usa.weather, europe.news, and europe.weather. |
AMQP 目前還是一個草案,最新版本是 0.10。
QPID 是 Apache Foundation 的一個開源項目,是一個 AMQP 實現。它提供了 C++ 和 Java 兩個版本的 broker,並支持多種語言的客戶端,它還包括一個配置工具集。
除了完全實現了 AMQP 的基本功能之外,Qpid 還提供了一些額外的特性:
- 採用 Corosync 來保證了集羣環境下的 Fault-tolerant 特性
- 支持 XML 類型的 Exchange,當消息格式爲 XML 時,可以利用 Xquery 進行過濾
- 支持 plugin,用戶可以方便地增加新的功能,比如新的 exchange 類型
- 提供了安全認證特性,任何 producer/consumer 需要和 broker 通信時,都需要提供身份認證,以便防止惡意的不相干的程序進入消息體系。QPID 的安全認證使用 SSL 協議。
使用 Qpid 編程
目前 Qpid 的最新版本是 0.10。從 0.6 版本開始,Qpid 的編程接口有了很大變化,之前的編程接口雖然繼續支持但已經過時。所以本文將掠過 0.5 的 API,直接介紹 Qpid Messaging API。
首先需要搭建一個實驗環境。
安裝
第一次看到 Qpid 的下載主頁時,我有點兒不知所措。過去,當我需要試用一個開源軟件時,在它的下載頁面上通常會看到一個 tar 包,最多不過是根據目標操作系統的不同,分成幾個 tar 包,只管下載相應的便可。但是 Qpid 的下載頁面卻有些讓我困惑,竟有衆多的按編程語言分類的 tar 包,一時之間也不知道下載哪個好。。。
如今似乎有些明白了,Qpid 是一個消息中間件,它大體分爲兩部分:broker 和 client 庫。
先來看 Client 庫,不同的編程語言,比如 Python,Ruby 等都需要其單獨的 client 包。這個很容易理解。
但 broker,Qpid 竟也有兩種實現 :C++ 和 Java。
Client 的選擇比較容易,您熟悉哪種語言便選擇哪個。但選擇 Java 的 Broker 還是 C++ 的 broker 卻會讓新手有些猶豫,相比之下選擇 KFC 還是麥當勞竟然是一件容易的事了。
java 版 broker 和 C++ 版 broker 各有優缺點,選擇也是因人而異。他們之間大部分特性相同,但也有不同,比如 Java 版的支持更多的 AMQP 版本;而 C++ 版本則支持 RDMA。QPID 社區將逐漸消除這些差異,但正如可口可樂和百事可樂共同存在這個世界上一樣,這兩個 broker 也終究會各有個的擁躉。Qpid 社區的資深開發者 Gordon Sim 回答某初學者的帖子對此應該很有幫助:http://fossplanet.com/f13/re-why-use-c-broker-versus-java-broker-71322/
本人對 java 基本上沒有什麼瞭解,對 C++ 和 python 則非常偏愛,所以打算使用 C++ 版本的 broker,client 端則採用 C++ 和 Python。
下載 Qpid broker 的安裝包,解壓,編譯,安裝:
tar xzvf ./configure make make install
經過以上幾步折騰,我們已經有了 C++ 的 broker 和 C++ 的 client 庫了。如果您想用 Python 編寫應用,那還需要下載 pyhonn 客戶端的 tar 包。
可喜的是 Python 無需編譯,因此所謂安裝只是設置一些環境變量而已。
這裏要提一下:如果您下載的是那個 full package,恐怕又需要費一點兒周折。該 package 包含了所有的東西 ( 各種語言的 broker 和 client),其中雖然也有 C++ 的 broker,但竟然和單獨下載的 C++ 包有所不同。到 cpp 目錄下,您看不到 configure 可執行文件。需要首先運行 bootstrap,初始化 autotools。
Bootstrap 之後,autoconfig 所需的條件便準備好了,之後便是常規的幾條安裝命令,總的來說如下:
./bootstrap ./configure make make install
希望您的安裝一切順利。
啓動 broker
最簡單的啓動方式爲
qpidd --port=60302 --no-data-dir --auth=no
以上啓動方式指定了三個主要的選項
--port 參數指定了 qpidd 監聽的端口號,默認爲 5672。
--no-data-dir 說明不需要指定數據持久化的目錄;當然您也可以指定一個目錄來存放持久化消息。
--auth=no 說明 qpidd 對所有的鏈接請求都不進行安全驗證。
其他的啓動參數在此不做詳細說明,讀者可以自行閱讀 help 信息。
管理 qpid
默認情況下,Broker 啓動之後,會自動創建一些 Exchange(交換器),對應 AMQP 標準定義的那幾個標準的 exchange 類型。分別叫做
- amp.topic
- amp.direct
- amp.fanout
應用程序可以建立 queue 並綁定到這些默認的 exchange 上進行信息收發。不過在真實的應用環境下,人們往往需要更多的 exchange,queue 以及 binding 來滿足各種各樣的需求。或者在一些複雜的網絡中還需要配置 broker 的聯邦,即一個相互路由的 broker 網絡。
凡此種種都需要對 broker 進行各種配置,比如添加新的 exchange,queue,添加 broker 路由等等,這些便需要使用 Qpid 提供的各種管理工具。除配置管理之外,Qpid 的管理工具還提供了監控功能。常用的工具有三個:
- Qpid-config
- Qpid-route
- Qpid-tool
Qpid-config 用來完成諸如添加 / 刪除 Queue,添加 / 刪除 Exchange 等關於 broker 內部的配置工作;Qpid-route 用來配置 broker Federation;Qpid-tool 用來對 Qpid Broker 進行實時監控。羅列他們的 help 信息對讀者沒有意義,我將在後面的例子中演示他們的一些用法。
程序代碼的基本框架
在一個採用了消息中間件的通信體系中有三個基本的角色,一個是發送消息的進程,一個是接受消息的進程,他們彼此之間通過 broker 連接起來,傳遞消息。
圖 2. 基本 Qpid 通信系統的幾個組件
Broker 無需編寫,如前所述,Qpid 實現了兩種 Broker,您只需要根據需要啓動其中之一既可。Sender 和 Receiver 則是需要用戶編寫的應用程序。這兩類程序都有一些基本的框架,在此簡要介紹一下。
首先他們都是 client,需要和 broker 進行連接。鏈接成功後便生成一個會話 Session。基本代碼如下:
清單 1. 基本的 Qpid 程序框架
新的 Messaging API 將複雜的 AMQP 的細節全部都隱藏了起來,極大地簡化了編程。
Address 地址
寫信的時候,人們需要地址。類似地在 Qpid 中,表示消息的目的地,或者源。
Qpid 的地址 Address 是一個帶格式的字符串,其語法如下:
其中 address,subject 和 key 都是字符串。
Subject 類似 email 的主題。每個消息都可以有一個主題,接收者可以通過主題對消息進行過濾。
Option 的具體含義有點兒複雜,可以參考 Qpid 的編程手冊獲取完整的描述。
Spout 和 Drain 的代碼
清單 2. Spout 代碼
可以看到 spout 首先用命令行參數 Address 初始化一個 Sender 對象,然後用 Sender 的 send 方法發送消息。
清單 3. Drain 代碼
點對點通信小例子
其二,信是唯一的,您寫給朋友的信一定不希望其他人也收到吧。在 Qpid 的 PTP 通信中,一個 Receiver 收到消息後,該消息就被消除,其他 Receiver 不能再收到。
現在我們建立了一個叫做 hello-world 的 queue。
這就相當於將信發給了 hello-world。您已經看到,此時接收者 drain 還沒有啓動,但 Queue 的存儲轉發特性保證 drain 還是可以收到這條消息:
當我們打開另外一個 shell 窗口執行 drain,會發現不會再收到這條消息了。
Browse 模式 vs Consume 模式
$ ./spout my-queue --content one $ ./spout my-queue --content two $ ./spout my-queue --content three
僅僅修改了
Address的
Option,我們就發現用
spout和
Drain可以實現另外一種通信模型了,這真是非常令人着迷的一個特性啊。
編寫 sub-pub 通信的例子
Pub-sub 是另一種很有用的通信模型。恐怕它的名字就源於出版發行這種現實中的信息傳遞方式吧,publisher 就是出版商,subscriber 就是訂閱者。
還是用 spout 和 drain 來演示,先運行 spout:
Pub-sub 的主要優點在於訂閱消息的靈活性,broker 會根據消息的主題分發給不同的 subscriber。比如我們創建一個 news-service 的 exchange:
打開兩個 shell 窗口,一個運行 drain 並訂閱 news-service/sport,體育新聞;另一個訂閱 news-service/ent 娛樂新聞:
可以看到不同的消息被自動分發給不同的訂閱者。第一個 shell 接收 sport 的 drain 將打印:
編寫 Request/Response 模型的應用
Server 必須知道是誰發送了請求,以便回覆給正確的 Requester。這是通過解析 Requester 發過來的消息中的 ReplyTo 字段得到的。
清單 4. Server 代碼
清單 5. Client 代碼
在 client 代碼中,我們需要調用 Message 的 setReplyTo 方法,設置回覆的地址。
小結
至此,我們看到了 Qpid 最基本的一些使用方法。演示了人們通常所使用的兩類通信模式,傳統的面向消息的中間件就實現了這兩個通信模型。但 Qpid 提供了一種更簡潔靈活的編程接口,僅通過修改 Address,無需修改代碼就可以改變應用程序的通信模型。
Qpid 是一個 AMQP 的實現,這意味這它不是一個私有的產品,使用 Qpid,您可以和其他任何符合 AMQP 協議的軟件系統進行通信。
不過假如這就是 Qpid 的全部,相信您一定也不以爲然,如果這些還不足以打動您,那麼我力圖在下一部分中向您介紹 Qpid 的一些高級特性。