當前,CORBA、DCOM、RMI等RPC中間件技術已廣泛應用於各個領域。但是面對規模和複雜度都越來越高的分佈式系統,這些技術也顯示出其侷限性:(1)同步通信:客戶發出調用後,必須等待服務對象完成處理並返回結果後才能繼續執行;(2)客戶和服務對象的生命週期緊密耦合:客戶進程和服務對象進程都必須正常運行;如果由於服務對象崩潰或者網絡故障導致客戶的請求不可達,客戶會接收到異常;(3)點對點通信:客戶的一次調用只發送給某個單獨的目標對象。
面向消息的中間件(Message Oriented Middleware,MOM)較好的解決了以上問題。發送者將消息發送給消息服務器,消息服務器將消息存放在若干隊列中,在合適的時候再將消息轉發給接收者。這種模式下,發送和接收是異步的,發送者無需等待;二者的生命週期未必相同:發送消息的時候接收者不一定運行,接收消息的時候發送者也不一定運行;一對多通信:對於一個消息可以有多個接收者。
已有的MOM系統包括IBM的MQSeries、Microsoft的MSMQ和BEA的MessageQ等。由於沒有一個通用的標準,這些系統很難實現互操作和無縫連接。Java Message Service(JMS)是SUN提出的旨在統一各種MOM系統接口的規範,它包含點對點(Point to Point,PTP)和發佈/訂閱(Publish/Subscribe,pub/sub)兩種消息模型,提供可靠消息傳輸、事務和消息過濾等機制。
1.JMS
JAVA 消息服務(JMS)定義了Java 中訪問消息中間件的接口。JMS 只是接口,並沒有給予實現,實現JMS 接口的消息中間件稱爲JMS Provider,iLink實現了JMS接口,用戶可以通過使用JMS接口,在iLink中進行JMS編程。 iLink支持JMS1.0.2版本。
2.JMS接口描述
JMS 支持兩種消息類型PTP 和Pub/Sub,分別稱作:PTP Domain 和Pub/Sub Domain,這兩種接口都繼承統一的JMS父接口,JMS 主要接口如下所示:
|
ConnectionFactory :連接工廠,JMS 用它創建連接
Connection :JMS 客戶端到JMS Provider 的連接
Destination :消息的目的地
Session: 一個發送或接收消息的線程
MessageProducer: 由Session 對象創建的用來發送消息的對象
MessageConsumer: 由Session 對象創建的用來接收消息的對象
3.JMS消息模型
JMS 消息由以下幾部分組成:消息頭,屬性,消息體。
3.1 消息頭(Header) - 消息頭包含消息的識別信息和路由信息,消息頭包含一些標準的屬性如:JMSDestination,JMSMessageID 等。
|
3.2 屬性(Properties) - 除了消息頭中定義好的標準屬性外,JMS 提供一種機制增加新屬性到消息頭 中,這種新屬性包含以下幾種:
1. 應用需要用到的屬性;
2. 消息頭中原有的一些可選屬性;
3. JMS Provider 需要用到的屬性。
標準的JMS 消息頭包含以下屬性:
|
3.3 消息體(Body) - JMS API 定義了5種消息體格式,也叫消息類型,你可以使用不同形式發送接收 數據並可以兼容現有的消息格式,下面描述這5種類型:
|
下例演示創建併發送一個TextMessage到一個隊列:
TextMessage message = queueSession.createTextMessage();
message.setText(msg_text); // msg_text is a String
queueSender.send(message);
下例演示接收消息並轉換爲合適的消息類型:
Message m = queueReceiver.receive();
if (m instanceof TextMessage) {
TextMessage message = (TextMessage) m;
System.out.println("Reading message: " + message.getText());
} else {
// Handle error
}
4. 消息的同步異步接收
消息的同步接收是指客戶端主動去接收消息,JMS 客戶端可以採用MessageConsumer 的receive方法去接收下一個消息。
消息的異步接收是指當消息到達時,主動通知客戶端。JMS 客戶端可以通過註冊一個實 現MessageListener 接口的對象到MessageConsumer,這樣,每當消息到達時,JMS Provider 會調用MessageListener中的onMessage 方法。
5. PTP模型
PTP(Point-to-Point)模型是基於隊列的,發送方發消息到隊列,接收方從隊列接收消息,隊列的存在使得消息的異步傳輸成爲可能。和郵件系統中的郵箱一樣,隊列可以包含各種消息,JMS Provider 提 供工具管理隊列的創建、刪除。JMS PTP 模型定義了客戶端如何向隊列發送消息,從隊列接收消息,瀏覽隊列中的消息。
下面描述JMS PTP 模型中的主要概念和對象:
|
6. PUB/SUB模型
JMS Pub/Sub 模型定義瞭如何向一個內容節點發布和訂閱消息,這些節點被稱作主題(topic)。
主題可以被認爲是消息的傳輸中介,發佈者(publisher)發佈消息到主題,訂閱者(subscribe)從主題訂閱消息。主題使得消息訂閱者和消息發佈者保持互相獨立,不需要接觸即可保證消息的傳送。
下面描述JMS Pub/Sub 模型中的主要概念和對象:
名稱
描述
訂閱(subscription)
消息訂閱分爲非持久訂閱(non-durable subscription)和持久訂閱(durable subscrip-tion),非持久訂閱只有當客戶端處於激活狀態,也就是和JMS Provider 保持連接狀態才能收到發送到某個主題的消息,而當客戶端處於離線狀態,這個時間段發到主題的消息將會丟失,永遠不會收到。持久訂閱時,客戶端向JMS 註冊一個識別自己身份的ID,當這個客戶端處於離線時,JMS Provider 會爲這個ID 保存所有發送到主題的消息,當客戶再次連接到JMS Provider時,會根據自己的ID 得到所有當自己處於離線時發送到主題的消息。
Topic
主題由JMS Provider 管理,主題由主題名識別,客戶端可以通過JNDI 接口用主題名得到一個主題對象。JMS 沒有給出主題的組織和層次結構的定義,由JMS Provider 自己定義。
TemporaryTopic
臨時主題由TopicConnection 創建,而且只能由創建它的TopicConnection 使用。臨時主題不能提供持久訂閱功能。
TopicConnectionFactory
客戶端用TopicConnectionFactory 創建TopicConnection 對象。
TopicConnection
TopicConnection 是一個到JMS Pub/Sub provider 的連接,客戶端可以用TopicConnection創建TopicSession 來發布和訂閱消息。
TopicSession
TopicSession 提供一些方法創建TopicPublisher、TopicSubscriber、TemporaryTopic 。它還提供unsubscribe 方法取消消息的持久訂閱。
TopicPublisher
客戶端用TopicPublisher 發佈消息到主題。
TopicSubscriber
客戶端用TopicSubscriber 接收發布到主題上的消息。可以在TopicSubscriber 中設置消息過濾功能,這樣,不符合要求的消息不會被接收。
Durable TopicSubscriber
如果一個客戶端需要持久訂閱消息,可以使用Durable TopicSubscriber,TopSession 提供一個方法createDurableSubscriber創建Durable TopicSubscriber 對象。
恢復和重新派送(Recovery and Redelivery)
非持久訂閱狀態下,不能恢復或重新派送一個未簽收的消息。只有持久訂閱才能恢復或重新派送一個未簽收的消息。
TopicRequestor
JMS 提供TopicRequestor 類簡化消息的收發過程。TopicRequestor 的構造函數有兩個參數:TopicSession 和topic。TopicRequestor 通過創建一個臨時主題來完成最終的發佈和接收消息請求。
可靠性(Reliability)
當所有的消息必須被接收,則用持久訂閱模式。當丟失消息能夠被容忍,則用非持久訂閱模式。
7. 開發JMS的步驟
廣義上說,一個JMS 應用是幾個JMS 客戶端交換消息,開發JMS 客戶端應用由以下幾步構成:
用JNDI 得到ConnectionFactory 對象;
用JNDI 得到目標隊列或主題對象,即Destination 對象;
用ConnectionFactory 創建Connection 對象;
用Connection 對象創建一個或多個JMS Session;
用Session 和Destination 創建MessageProducer 和MessageConsumer;
通知Connection 開始傳遞消息。
XA分佈式事務處理
分佈式事務處理是指一個事務可能涉及多個數據庫操作,分佈式事務處理的關鍵是必須有一種方法可以知道事務在任何地方所做的所有動作,提交或回滾事務的決定必須產生統一的結果(全部提交或全部回滾)。
X/Open 組織(即現在的 Open Group )定義了分佈式事務處理模型。 X/Open DTP 模型( 1994 )包括應用程序( AP )、事務管理器( TM )、資源管理器( RM )、通信資源管理器( CRM )四部分。一般,常見的事務管理器( TM )是交易中間件,常見的資源管理器( RM )是數據庫,常見的通信資源管理器( CRM )是消息中間件。
通常把一個數據庫內部的事務處理,如對多個表的操作,作爲本地事務看待。數據庫的事務處理對象是本地事務,而分佈式事務處理的對象是全局事務。
所謂全局事務,是指分佈式事務處理環境中,多個數據庫可能需要共同完成一個工作,這個工作即是一個全局事務,例如,一個事務中可能更新幾個不同的數據庫。對數據庫的操作發生在系統的各處但必須全部被提交或回滾。此時一個數據庫對自己內部所做操作的提交不僅依賴本身操作是否成功,還要依賴與全局事務相關的其它數據庫的操作是否成功,如果任一數據庫的任一操作失敗,則參與此事務的所有數據庫所做的所有操作都必須回滾。
一般情況下,某一數據庫無法知道其它數據庫在做什麼,因此,在一個 DTP 環境中,交易中間件是必需的,由它通知和協調相關數據庫的提交或回滾。而一個數據庫只將其自己所做的操作(可恢復)影射到全局事務中。 XA 就是 X/Open DTP 定義的交易中間件與數據庫之間的接口規範(即接口函數),交易中間件用它來通知數據庫事務的開始、結束以及提交、回滾等。 XA 接口函數由數據庫廠商提供。
XA 與兩階段提交協議
通常情況下,交易中間件與數據庫通過 XA 接口規範,使用兩階段提交來完成一個全局事務, XA 規範的基礎是兩階段提交協議。
在第一階段,交易中間件請求所有相關數據庫準備提交(預提交)各自的事務分支,以確認是否所有相關數據庫都可以提交各自的事務分支。當某一數據庫收到預提交後,如果可以提交屬於自己的事務分支,則將自己在該事務分支中所做的操作固定記錄下來,並給交易中間件一個同意提交的應答,此時數據庫將不能再在該事務分支中加入任何操作,但此時數據庫並沒有真正提交該事務,數據庫對共享資源的操作還未釋放(處於上鎖狀態)。如果由於某種原因數據庫無法提交屬於自己的事務分支,它將回滾自己的所有操作,釋放對共享資源上的鎖,並返回給交易中間件失敗應答。 在第二階段,交易中間件審查所有數據庫返回的預提交結果,如所有數據庫都可以提交,交易中間件將要求所有數據庫做正式提交,這樣該全局事務被提交。而如果有任一數據庫預提交返回失敗,交易中間件將要求所有其它數據庫回滾其操作,這樣該全局事務被回滾。
以一個全局事務爲例, AP 首先通知交易中間件開始一個全局事務,交易中間件通過 XA 接口函數通知數據庫開始事務,然後 AP 可以對數據庫管理的資源進行操作,數據庫系統記錄事務對本地資源的所有操作。操作完成後交易中間件通過 XA 接口函數通知數據庫操作完成。交易中間件負責記錄 AP 操作過哪些數據庫(事務分支)。 AP 根據情況通知交易中間件提交該全局事務,交易中間件會通過 XA 接口函數要求各個數據庫做預提交,所有數據庫返回成功後要求各個數據庫做正式提交,此時一筆全局事務結束。
XA 規範對應用來說,最大好處在於事務的完整性由交易中間件和數據庫通過 XA 接口控制, AP 只需要關注與數據庫的應用邏輯的處理,而無需過多關心事務的完整性,應用設計開發會簡化很多。