WebSphere MQ Low Latency Messaging 產品介紹及 API 使用

CloudSpace發表於2010-07-26
王 貝貝 (wangbeib@cn.ibm.com), 軟體工程師, IBM
 
簡介: IBM WebSphere MQ Low Latency Messaging 提供了一種高吞吐量、低延遲的訊息傳遞方法。本文介紹該產品的用途和主要特點,並詳細闡述 Reliable Multicast Messaging 和 Reliable Unicast Messaging 兩種訊息傳輸方式和 API 使用,以及典型的測試場景和測試方法。
 

引言

IBM WebSphere MQ Low Latency Messaging(以下簡稱 MQ LLM)提供了一種高吞吐量、低延遲的訊息傳遞方法。在金融市場和其它一些需要高速資料交換的應用場景中,訊息傳遞需要滿足極高容量、低延遲的需求,MQ LLM 能夠有效滿足這種需求。本文首先介紹 MQ LLM 的用途和主要特點,然後詳細闡述 Reliable Multicast Messaging(RMM)和 Reliable Unicast Messaging(RUM)兩種訊息傳輸方式及其 API 的使用方法,並描述了測試場景。

 

MQ LLM 產品介紹

IBM WebSphere MQ Low Latency Messaging,最初來源於 IBM Haifa 實驗室,而後作為 WebSphere Front Office for Financial Markets(以下簡稱 WFO)市場資料交付平臺的高效能資訊元件處理金融市場資料,2.0 版本的釋出使其獨立出來作為一個單獨的產品。MQ LLM 提供了一種高吞吐量、低延遲的訊息傳遞方法,在金融領域,結合 WFO,它能夠滿足高速運轉的金融市場的爆炸性資料分析的應用需求,幫助金融企業改善其管理複雜金融市場資料的能力;在市場運輸行業,也存在著大量的實時市場資訊分析及物流資訊管理的應用需求,它能夠大大提高市場運輸行業的資料分發效能和能力。海量資料的低延遲傳輸是資料交付速度至關重要行業的典型需求,MQ LLM 能夠顯著降低傳輸延時,提供可靠的資料交付和流故障轉移,訊息過濾以及控制流量速率擁塞等多種選擇,使大量資料能夠以滿足急迫業務要求的速度傳輸。目前,該產品已成功應用於金融市場領域解決方案。

MQ LLM 具有如下核心特性:

  1. 高吞吐量、低延遲:採用分組、包丟失處理等策略提高效能,使得訊息(12-byte)傳送速率能夠達到每秒千萬級,在 1G 乙太網上的延遲實現微妙級。
  2. 多播和單播的支援:包括可靠的 UDP 多播(RMM),可靠的 UDP 單播(點對點的 RMM)以及可靠的 TCP 單播(RUM)。
  3. 可靠性:與 2 中的多播和單播支援相對應,UDP 多播的可靠性由 NAK 可靠性、滑動視窗、擁塞管理來保證,UDP 單播的可靠性由 ACK 可靠性、週期心跳檢測來實現,TCP 單播的可靠性依賴於 TCP 的可靠性。
  4. 訊息過濾機制:通過訊息屬性進行過濾。
  5. 擁塞管理:自動發現並採取相應策略處理慢速消費者(處理訊息速度比較慢的接收方)。
  6. 系統支援:能夠執行在 Windows(32,64),Linux(32,64),Solaris(Sparc,x86,32,64)平臺上;提供 C,Java 支援和 .NET API,監控 API 可以獲得網路狀態、傳送方、接收方、延遲統計等資訊。
 

RMM 和 RUM 概覽

首先,回顧一下傳輸層協議和網路節點間的通訊模式。

傳輸層有兩種傳輸協議:UDP 和 TCP。

  • UDP(User Data Protocol,使用者資料包協議):是一種無連線的不可靠傳輸層協議。在正式通訊前,不與對方建立連線,直接傳送資料,適用於傳輸效率要求高、對可靠性要求較低的應用環境。
  • TCP(Transmission Control Protocol,傳輸控制協議):是一種面向連線的可靠傳輸層協議。在正式通訊之前,必須要與對方建立可靠連線,由於採用滑動視窗、慢啟動等機制,效率低於 UDP,適用於對可靠性要求高的應用環境。

網路節點之間有三種通訊模式:單播、廣播、多播。

  • 單播(Unicast):點對點通訊模式,資料的接收和傳遞只在兩個節點之間進行。
  • 多播(Multicast):點對多通訊模式,也稱之為“組播”,一次傳送到一組特定目標節點。
  • 廣播(Broadcast):IP 子網內的所有主機都可以接收到所有資訊。

在 MQ LLM 中,有兩種訊息傳輸方式:RMM 和 RUM。

  • RMM(Reliable Multicast Messaging):基於 UDP 協議,支援可靠的單播和多播傳輸。
  • RUM(Reliable Unicast Messaging):基於 TCP 協議,提供一對一的單播傳輸。
  • RMM 和 RUM 實現機制不同,但都需要定義傳送方、接收方,通訊的邏輯通道、物理通道、訊息等,表 1 描述了 RMM 和 RUM 中的物件。

表 1. RMM 和 RUM 中的物件描述
RMM RUM
例項(Instance) 傳送方或接收方物件本身
主題(Topic) 傳送方和接收方之間通訊的邏輯通道。傳送方、接收方需要分別建立傳送主題、接收主題。
連線(Connection) RUM 基於 TCP 協議,傳送方和接收方在傳送資料前需要建立連線。
佇列(Queue) 傳送方和接收方之間通訊的邏輯通道。在建立傳送佇列時需要一個已經存在的連線,建立接收佇列時不需要。
流(Stream) 一個傳送主題對應一個流,多個流可以對應一個接收主題。 多個流可以對應一個傳送方或接收方。
訊息(Message) 傳送方和接收方之間傳輸的資料。包括原始資料、屬性等。

 

MQ LLM 的 API 使用

MQ LLM API 提供了對 C,Java,.NET 開發語言的支援,本文主要介紹 MQ LLM Version 2.1.0.0 的 Java API 使用。用 Java 程式設計,要使用 llmJni.jar 類庫,可以在 LLM 安裝後的 lib 目錄下獲得,內容如圖 1 所示。com.ibm.llm.rmm/rum 下分別有如下六個包:common(常用類),config(配置類),constants(資料結構類),exception(異常處理類),impl(實現類),monitoring(監控統計類)。


圖 1. Java 程式設計類庫 llmJni.jar
圖 1. Java 程式設計類庫 llmJni.jar

該類庫提供了 RMM 和 RUM 兩種訊息傳輸方式的 API,能夠處理訊息的傳送和接收,並獲得統計資料。下面詳細描述在 RMM 和 RUM 中如何對傳送方和接收方程式設計。

RMM API 的使用

RMM 的訊息傳輸過程如圖 2 所示:在傳送方部署 Transmitter,在每個接收方部署 Receiver。由於 RMM 可以支援單播和多播,單播時 Receiver 只需要部署在一個接收方,而多播時需要部署在多播組內的每個接收方。首先,啟動 Receiver(s),建立接收方例項、接收主題,並加入多播組,監聽訊息;然後,啟動 Transmitter,建立傳送方例項、傳送主題,建立訊息通道傳送訊息,Receiver 接收訊息;在一定條件下(如傳送 10000 條訊息)結束髮送;傳送方、接收方分別關閉主題、停止例項。


圖 2. RMM 的訊息傳輸過程
圖 2. RMM 的訊息傳輸過程

Transmitter API

  1. 建立傳送方例項

    RmmTransmitter 類定義了 RMM 傳送方例項,由 RmmFactory 建立。RmmFactory 提供了兩個方法建立傳送方例項。

    方法一,需要先建立傳送方配置 RmmTxConfig,設定配置項,然後基於此配置建立傳送方例項(清單 1)。



    清單 1. 建立 RMM 傳送方例項
    				 
     // 建立傳送方配置
     RmmTxConfig config_t = new RmmTxConfig(); 
     // 設定配置項
     config_t.dataPort = 34343; 
     ... 
    
     RmmTransmitter transmitter = null; 
     // 基於配置建立傳送方例項
     try { 
     transmitter = RmmFactory.initRmmTransmitter(config_t); 
     } catch (RmmException e) { 
    	 System.out.println("fail to initialize the transmitter. " + e.getReason()); 
     } 
    

    方法二,基於預設配置建立(清單 2)。傳送預設配置在 rmmTbasic.cfg 和 rmmTadvanced.cfg 檔案中定義,用 key=value 的鍵值描述引數名值。rmmTbasic.cfg 和 rmmTadvanced.cfg 分別定義了基本配置引數和高階配置引數,開發者可以參考 %llm%/perfsamples/configs 中的配置,在測試過程中根據引數意義和實際環境進行設定。這裡建議採用方法二,在除錯和優化時可以通過修改配置檔案調整引數值,程式碼不需要任何變動。



    清單 2. 建立 RMM 傳送方例項(基於預設配置)
    				 
     RmmTransmitter transmitter = null; 
     // 基於預設配置建立傳送方例項
     try { 
     transmitter = RmmFactory.initRmmTransmitterUsingDefaultConfig(); 
     } catch (RmmException e) { 
     System.out.println("fail to initialize the transmitter." + e.getReason()); 
     } 

  2. 建立傳送主題

    建立傳送主題有兩個步驟(清單 3):

    • 建立傳送主題引數 RmmTxTopicParameters:設定主題名稱,目的地址,傳輸型別等。

      RMM 支援多播和單播,因此傳輸型別要指定是多播 RmmTransportType.RMM_TRANSPORT_MULTICAST 或者單播 RmmTransportType.RMM_TRANSPORT_UDP_UNICAST。

      設定訊息回撥事件,為該主題設定回撥類,實現 RmmEventListener 介面,根據 event 型別的不同,輸出對應的提示資訊(清單 4)。

    • 建立傳送主題 RmmTxTopic:在傳送方上建立傳送主題。


    清單 3. 建立 RMM 傳送主題
    				 
     // 建立傳送主題引數
     RmmTxTopicParameters topicParams_t = new RmmTxTopicParameters(); 
     // 設定主題名稱
     String txTopicName = "RMMTestTopic"; 
     topicParams_t.topicName = txTopicName; 
     // 設定目的地址
     topicParams_t.destAddress = "239.255.1.5"; 
     try { 
          // 設定傳輸型別為多播 
          topicParams_t.transport.setValue(RmmTransportType.RMM_TRANSPORT_MULTICAST); 
          // 設定可靠性 
          topicParams_t.reliability.setValue(RmmTxReliabilityType.RMM_RELIABLE); 
     } catch (RmmInvalidValueException e) { 
     System.out.println("fail to set topic parameters. " + e.getReason()); 
     } 
     // 設定訊息回撥事件
     topicParams_t.onEvent = new RmmCustomizedEventListener(); 
    
     // 建立傳送主題
     RmmTxTopic txTopic = null; 
     try { 
    	 txTopic = transmitter.createTopic(topicParams_t); 
     } catch (RmmException e) { 
     System.out.println("fail to create topic " + txTopicName + "." + e.getReason()); 
     } 
    



    清單 4. 訊息回撥事件
    				
    public class RmmCustomizedEventListener implements RmmEventListener { 
      publicvoid onEvent(RmmEvent event) { 
      Date eventTime = new Date(); 
     switch(event.type.getValue()) { 
     case RmmEventType.RMM_MESSAGE_LOSS: 
                    // 輸出丟失訊息資訊
     System.out.println(eventTime.toString() + "> message loss on topic " 
      + event.topicName + " from " + event.sourceAddr + ":" + event.port); 
     casedefault: 
                     // 輸出收到訊息資訊
     System.out.println(eventTime.toString() + "> received event "
      + event.type.toString() + " on topic " + event.topicName 
      + " from " + event.sourceAddr + ":" + event.port); 
    		 } 
    	 } 
     } 

  3. 傳送訊息

    RmmTxMessage 類定義了訊息,填充訊息內容和大小後,在一個主題上傳送訊息(清單 5)。主程式應當控制訊息的傳送數量和頻率,可以採用執行緒實現。



    清單 5. 傳送訊息
    				  
     // 建立訊息
     RmmTxMessage msg = new RmmTxMessage(); 
     byte[] bytes = new byte[1024]; 
     msg.msgBuf = bytes; 
     msg.msgLen = bytes.length; 
    
     // 傳送訊息
     try { 
    	 txTopic.submitMessage(msg); 			
     } catch (RmmException e) { 
     System.out.println("fail to submit message for the topic" + txTopicName); 
     } 

  4. 關閉傳送主題

    關閉傳送方在該主題上的訊息傳輸(清單 6),其它主題不受影響。關閉主題後,訊息不能繼續在該主題上傳送,接收方會自動得知流關閉,但仍可以在延遲時間(closeTopic 方法引數)內接收資料。超時後,主題將會徹底刪除。



    清單 6. 關閉 RMM 傳送主題
    				 
     // 關閉傳送主題
     try { 
    	 txTopic.closeTopic(0); 
     } catch (RmmException e) { 
     System.out.println("fail to close transmitter topic." + e.getReason()); 
     } 
    

  5. 停止傳送方例項

    停止指定的傳送方例項(清單 7),傳送方可在延遲時間內(stopTransmitter 方法引數)傳送等待傳送的資料,超時後停止。



    清單 7. 停止 RMM 傳送方例項
    				 
     // 停止傳送端例項
     try { 
    	 transmitter.stopTransmitter(0); 
     } catch (RmmException e) { 
     System.out.println("fail to stop transmitter instance." + e.getReason()); 
     } 
    

Receiver API

  1. 建立接收方例項

    由 RmmFactory 建立接收方例項 RmmReceiver,也有類似基於 RmmRxConfig 和基於預設配置建立兩種方法。示例中基於預設配置建立(清單 8),接收預設配置在 rmmRbasic.cfg 和 rmmRadvanced.cfg 檔案中定義。



    清單 8. 建立 RMM 接收方例項
    				 
     RmmReceiver receiver = null; 
     try { 
     receiver = RmmFactory.initRmmReceiverUsingDefaultConfig(); 
     } catch (RmmException e) { 
     System.out.println("fail to initialize the receiver." + e.getReason()); 
     } 
    

  2. 建立接收主題,加入多播組

    與建立傳送主題類似,需要先建立主題引數 RmmRxTopicParameters,再建立主題 RmmRxTopic(清單 9)。此時需要注意以下幾點:

    • 主題名稱:接收主題名稱要與傳送發主題名稱一致,如示例中均為 RMMTestTopic,這樣傳送方上傳送到該主題的訊息才能被接收。
    • 加入多播組:加入該多播組 239.255.1.5 之後,才能收到傳送發發到該地址的訊息,這裡地址需要與傳送主題設定的目的地址一致。
    • 訊息處理事件:偵聽該主題上收到的訊息並處理。


    清單 9. 建立 RMM 接收主題,加入多播組
    				 
     // 建立接收主題引數
     RmmRxTopicParameters topicParams_r = new RmmRxTopicParameters(); 
     // 設定主題名稱
     String rxTopicName = "RMMTestTopic"; 
     topicParams_r.topicName = rxTopicName; 
     try { 
          // 設定可靠性
     topicParams_r.reliability.setValue(RmmRxReliabilityType.RMM_RELIABLE_ORDERED); 
     } catch (RmmInvalidValueException e) { 
     System.out.println("fail to set topic parameters." + e.getReason()); 
     } 
    
     // 設定訊息回撥事件
     topicParams_r.onEvent = new RmmCustomizedEventListener(); 
     // 設定訊息處理事件
     topicParams_r.onMessage = new RmmCustomizedMessageListener(); 
    
     try { 
          // 加入多播組
    	 receiver.joinMulticastGroup("239.255.1.5"); 
     } catch (RmmException e) { 
     System.out.println("fail to join multicast group." + e.getReason()); 
     } 
    
     // 建立接收主題
     RmmRxTopic rxTopic = null; 
     try { 
    	 rxTopic = receiver.createTopic(topicParams_r); 
     } catch (RmmException e) { 
     System.out.println("fail to create topic " + rxTopicName + ". " + e.getReason()); 
     } 
    

  3. 接收訊息

    偵聽該主題上收到的訊息,對訊息進行處理。Listener 實現 RmmMessageListener 介面,每次收到訊息時,onMessage 方法都會被呼叫。如示例中計算訊息延遲時間,其中傳送時間可以在傳送訊息時附帶(清單 10)。



    清單 10. 接收訊息
    				
    public class RmmCustomizedMessageListener implements RmmMessageListener { 
     public void onMessage(RmmRxMessage msg) { 
                // 訊息收到時間
           long receiveTime = System.nanoTime(); 
                // 訊息傳送時間
              long transmitTime = …
                // 計算延遲時間
     int latency = (int)((receiveTime - transmitTime) * 1.0e-3); 
    	 } 
     } 
    

  4. 離開多播組

    接收方離開多播組後,不再收到傳送到該組地址的訊息,該步驟只需在必要時操作(清單 11)。



    清單 11. 離開多播組
    				 
     // 離開多播組
     try { 
          receiver.leaveMulticastGroup("239.255.1.5"); 
     } catch (RmmException e) { 
          System.out.println("fail to leave multicast group." + e.getReason()); 
     } 
    

  5. 關閉接收主題

    關閉接收主題後,不會再接收訊息。如果還有正在處理的訊息,會丟擲 RmmBusyException,表示此時不能刪除該訊息,應當稍後再試圖關閉(清單 12)。



    清單 12. 關閉 RMM 接收主題
    				 
     // 關閉接收主題
     try { 
    	 rxTopic.closeTopic(); 
     } catch (RmmBusyException e) { 
     // 稍後關閉
          …
     } catch (RmmException e) { 
     System.out.println("fail to close receiver topic." + e.getReason()); 
     } 
    

  6. 停止接收方例項

    停止接收訊息,釋放資源(清單 13)。



    清單 13. 停止 RMM 接收方例項
    				 
     // 停止接收方例項
     try { 
    	 receiver.stopReceiver(); 
     } catch (RmmException e) { 
     System.out.println("failed to stop RMM receiver instance." + e.getReason()); 
     } 
    

RUM API 的使用

RUM 的訊息傳輸過程如圖 3 所示:在傳送方部署 Transmitter,在接收方部署 Receiver。由於 RUM 是基於 TCP 的可靠傳輸,需要在事先建立連線。首先,啟動 Receiver,建立接收方例項、接收佇列;然後,啟動 Transmitter,建立傳送方例項,建立連線;在得到確認連線後,建立傳送佇列、傳送訊息,Receiver 接收訊息;傳送結束後,傳送方關閉連線,傳送方、接收方分別關閉主題、停止例項。


圖 3. RUM 的訊息傳輸過程
圖 3. RUM 的訊息傳輸過程

下述 RUM 的 API 介紹重點突出與 RMM 不同的部分,並省略了異常處理,讀者可參考 RMM 中的示例。

Transmitter API

  1. 建立傳送方例項

    RUM 的傳送方例項、接收方例項都由 RumInstance 類定義(清單 14),預設配置檔案均為 rumbasic.cfg 和 rumAdvanced.cfg。



    清單 14. 建立 RUM 傳送方例項
    				 
     // 基於預設配置建立傳送方例項
     RumInstance transmitter = RumFactory.initRumInstanceUsingDefaultConfig(); 
    

  2. 建立連線

    與接收方建立連線,指定接收方的地址和埠,並偵聽連線響應(清單 15)。RumCustomizedTransmitterConnListener 實現 RumConnectionListener 介面,接收方響應後,在 onConnectionEvent 方法中獲得是否成功建立連線(清單 16)。



    清單 15. 建立連線
    				 
     // 設定連線引數
     RumEstablishConnectionParams connParams = new RumEstablishConnectionParams(); 
     connParams.address = "9.186.113.28"; 
     connParams.port = 35353; 
     // 偵聽連線響應
     RumCustomizedTransmitterConnListener transmitterConn = 
        new RumCustomizedTransmitterConnListener(); 
     connParams.connectionListener = transmitterConn; 
     // 建立連線
     transmitter.establishConnection(connParams); 
    



    清單 16. 偵聽連線響應
    				
    public class RumCustomizedTransmitterConnListener implements RumConnectionListener { 
    	
     private RumConnection conn; 
      private int connEventType = RumConnEventType.RUM_CONNECTION_ESTABLISH_IN_PROCESS; 
    	
      public RumConnection getConn() { return conn; } 
    	
       public int getConnEventType() { return connEventType; } 
    
      public int onConnectionEvent(RumConnectionEvent connEvent) { 
    		 connEventType = connEvent.type.getValue(); 
       switch (connEventType) { 
        case RumConnEventType.RUM_CONNECTION_ESTABLISH_SUCCESS: 
    			 conn = connEvent.connectionInfo; 
                      // 確認連線
         return
    				RUM_ON_CONNECTION_ACCEPT; 
         case RumConnEventType.RUM_NEW_CONNECTION: 
         case RumConnEventType.RUM_CONNECTION_READY: 
                      // 拒絕連線
         return
    				RUM_ON_CONNECTION_REJECT; 
         case RumConnEventType.RUM_CONNECTION_ESTABLISH_FAILURE: 
         case RumConnEventType.RUM_CONNECTION_ESTABLISH_IN_PROCESS: 
         case RumConnEventType.RUM_CONNECTION_ESTABLISH_TIMEOUT: 
         default: 
         return
    				RUM_ON_CONNECTION_NULL; 
    		 } 
    	 } 
    
     } 
    

  3. 建立傳送佇列

    在接收方同意連線後,建立傳送佇列(清單 17)。



    清單 17. 建立 RUM 傳送佇列
    				 
     // 等待響應
    while 
      (transmitterConn.getConnEventType() == 
        RumConnEventType.RUM_CONNECTION_ESTABLISH_IN_PROCESS); 
    if (transmitterConn.getConn() == null) 
    new Exception("fail to establish the connection."); 
    
     // 建立傳送佇列引數
     RumTxQueueParameters queueParams_t = new RumTxQueueParameters(); 
     queueParams_t.rumConnection = transmitterConn.getConn(); 
     queueParams_t.queueName = "RUMTestQueue"; 
     queueParams_t.reliability 
       = new RumTxReliabilityType(RumTxReliabilityType.RUM_RELIABLE); 
    
     // 建立傳送佇列
     RumTxQueue txQueue = transmitter.createTxQueue(queueParams_t); 
    

  4. 傳送訊息

    建立訊息 RumTxMessage,併傳送到佇列上(清單 18)。



    清單 18. 傳送訊息
    				 
    // 建立訊息
    RumTxMessage msg = new RumTxMessage();
    …
    // 傳送訊息
    txQueue.submitMessage(msg);
    

  5. 關閉傳送佇列
     txQueue.closeQueue(0); 
    

  6. 關閉連線
     transmitter.closeConnection(transmitterConn.getConn()); 
    

  7. 停止傳送方例項
     transmitter.stopInstance(0); 
    

Receiver API

  1. 建立接收方例項
     RumInstance receiver = RumFactory.initRumInstanceUsingDefaultConfig(); 
    

  2. 建立接收佇列

    在接收佇列引數中,接收佇列名稱應與傳送佇列名稱匹配,並設定 Listener 偵聽該佇列上的訊息(清單 19)。



    清單 19. 建立 RUM 接收佇列
    				 
     // 建立接收佇列引數
     RumRxQueueParameters queueParams_r = new RumRxQueueParameters(); 
     queueParams_r.queueName = "RUMTestQueue"; 
     queueParams_r.onMessage = new RumCustomizedMessageListener(); 
     queueParams_r.reliability = 
         new RumRxReliabilityType(RumRxReliabilityType.RUM_RELIABLE); 
    
     // 建立接收佇列
     RumRxQueue rxQueue = receiver.createRxQueue(queueParams_r); 
    

  3. 確認連線

    當收到一個新的連線請求 RUM_NEW_CONNECTION 時,確認連線(清單 20)。



    清單 20. 確認連線
    				 
     receiver.addConnectionListener(new RumCustomizedReceiverConnListener()); 
    
    public class RumCustomizedReceiverConnListener implements RumConnectionListener { 
      public int onConnectionEvent(RumConnectionEvent connEvent) { 
         switch (connEvent.type.getValue()) { 
           case RumConnEventType.RUM_NEW_CONNECTION: 
            case RumConnEventType.RUM_CONNECTION_READY: 
                      // 確認連線
          return
    				RUM_ON_CONNECTION_ACCEPT; 
          case RumConnEventType.RUM_CONNECTION_BROKE: 
          case RumConnEventType.RUM_CONNECTION_CLOSED: 
          case RumConnEventType.RUM_CONNECTION_ESTABLISH_FAILURE: 
          case RumConnEventType.RUM_CONNECTION_ESTABLISH_IN_PROCESS: 
          case RumConnEventType.RUM_CONNECTION_ESTABLISH_TIMEOUT: 
          return
    				RUM_ON_CONNECTION_NULL; 
          case RumConnEventType.RUM_CONNECTION_ESTABLISH_SUCCESS: 
         default: 
         return
    				RUM_ON_CONNECTION_REJECT; 
    		 } 
    	 } 
     } 
    

  4. 接收訊息

    Listener 實現 RumMessageListener 介面,對訊息的處理封裝在 onMessage 方法中,例如統計收到的訊息數量或計算延遲(清單 21)。



    清單 21. 接收訊息
    				
    public class RumCustomizedMessageListener implements RumMessageListener { 
     public void onMessage(RumRxMessage msg) { 
     // 處理訊息
                …
    	 } 
     } 
    

  5. 關閉接收佇列
     rxQueue.closeQueue(); 
    

  6. 停止接收方例項

    receiver.stopInstance(0);

 

效能評測方法

MQ LLM 的特點是高吞吐量、低延遲,因此吞吐量、延遲這兩個引數是該產品效能評測的重要依據,下面簡單描述 RMM 單播時的測試方法。

吞吐量是指在沒有訊息丟失的情況下,能夠接收訊息的最大速率。測量該引數,如圖 4 所示,在機器 A 部署 Transmitter,在機器 B 上部署 Receiver。啟動 Receiver 監聽傳送到“ThroughputTest”主題的訊息;啟動 Transmitter,傳送訊息。在 Transmitter 設定不同的傳送頻率,當接收方出現訊息丟失或者無法接收訊息時的的最大傳送頻率,即吞吐量。


圖 4. 吞吐量測試方法
圖 4. 吞吐量測試方法

延遲是指訊息從傳送方到接收方所用的時間。由於傳送方和接收方的時鐘不能保證同步,因此可以採用接收方再回送訊息的方法來計算延遲。如圖 5 所示,在機器 A 上部署 TransmitterA 和 ReceiverA(分別部署),在機器 B 上部署 ReceiverB 和 TransmitterB(打包在一起部署)。啟動 ReceiverA 監聽回送訊息;啟動 ReceiverB 和 TransmitterB,監聽傳送到“LatencyTest”主題的訊息;啟動 TransmitterA,傳送訊息;ReceiverB 接收到訊息後,TransmitterB 將該訊息傳送到“LatencyBackTest”主題上;ReceiverA 收到回送訊息。通過在傳送訊息時在訊息上留下的時間戳,在收到回送訊息時獲得當前時間,可計算出往返用時 T1+T2。延遲時間 T 近似為(T1+T2)/2,在機器 B 中的轉發用時忽略不計。


圖 5. 延遲測試方法
圖 5. 延遲測試方法

另外,開發者也可以藉助 MQ LLM 提供的監控 API,獲得統計資訊,具體可參見物件的 fetchStatistics 方法,以及 API 的 com.ibm.llm.rmm.monitoring 包。

 

總結

本文介紹了 MQ LLM 的產品特性及其支援的 RMM 和 RUM 兩種傳輸方式,重點描述了 RMM 和 RUM 傳送方、接收方 API 的使用,未涉及到效能的除錯和優化等高階主題。讀者通過本文能夠快速熟悉產品 API,構建傳輸場景,進行引數測定。

宣告:本文僅代表作者個人之觀點,不代表 IBM 公司之觀點。

 

原文連結:http://www.ibm.com/developerworks/cn/websphere/library/techarticles/1007_wangbb_mqllm/1007_wangbb_mqllm.html

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14789789/viewspace-669488/,如需轉載,請註明出處,否則將追究法律責任。

相關文章