JMS性能測試方案
JMS綜述
1、相關概念
1)JMS
jms即Java消息服務(Java Message Service) 是一個Java平臺中關于面向消息中間件(MOM)的API,用于在兩個應用程序之間,或分布式系統中發送消息,進行異步通信。Java消息服務是一個與具體平臺無關的API,絕大多數MOM提供商都對JMS提供支持,它提供標準的產生、發送、接收消息的接口簡化企業應用的開發。是一組接口和相關語義的集合,定義了JMS客戶端如何獲取企業消息產品的功能。JMS并不是一個MOM。它是一個API,抽象了客戶端和MOM的交互,就像JDBC抽象與數據庫的交互一樣。
2)MOM
消息中間件MOM的設計原理就是作為消息發送者和接收者的中間人。這個中間人提供了一個高級別的解耦,實現應用間的交互。 在一個較高級別看,消息就是一個商業信息單元,它通過MOM從一個應用發送到另一個應用。應用使用目標(destinations)來發送和接收消息。消息將被投遞到destinations,然后發送給連接或訂閱該destinations的接收者。這個機制能夠解耦消息的發送者和接收者,因為它們在發送或接收消息的時候并不需要同時連接ActiveMQ。發送者不了解接收者,接收者也不了解發送者。這個機制就叫做異步消息傳送。
3)MQ
MQ全稱為Message Queue, 消息隊列(MQ)是一種應用程序對應用程序的通信方法。應用程序通過寫和檢索出入列隊的針對應用程序的數據(消息)來通信,而無需專用連接來鏈接它們。消息傳遞指的是程序之間通過在消息中發送數據進行通信,而不是通過直接調用彼此來通信,直接調用通常是用于諸如遠程過程調用的技術。排隊指的是應用程序通過隊列來通信。隊列的使用除去了接收和發送應用程序同時執行的要求。其中較為成熟的MQ產品有IBMWEBSPHERE MQ。
MQ的消費-生產者模型的一個典型的代表,一端往消息隊列中不斷的寫入消息,而另一端則可以讀取或者訂閱隊列中的消息。MQ和JMS類似,但不同的是JMS是SUN JAVA消息中間件服務的一個標準和API定義,而MQ則是遵循了AMQP協議的具體實現和產品。JMS是一個用于提供消息服務的技術規范,它制定了在整個消息服務提供過程中的所有數據結構和交互流程。而MQ則是消息隊列服務,是面向消息中間件(MOM)的最終實現,是真正的服務提供者;MQ的實現可以基于JMS,也可以基于其他規范或標準。支持JMS的開源MQ目前選擇的最多的是ActiveMQ。其他開源JMS供應商:jbossmq(jboss 4)、jboss messaging (jboss 5)、joram、openjms、mantamq、ubermq、SomnifugiJMS等等。
4)SOAP與JMS
SOAP使用RPC(遠程過程調用)和消息傳遞來建立通信服務,SOAP RPC定義了用于表示遠程過程調用和應答的協議。SOAP協議本身僅僅定義了消息的交換結構,它可以和許多現存因特網協議結合在一起使用,其中包括超文本傳輸協議( HTTP),多用途網際郵件擴充協議(MIME),Java 消息服務(JMS)以及簡單郵件傳輸協議(SMTP)等。目前與SOAP應用最為廣泛的是HTTP協議和JMS協議,而與之相對應的兩種應用就是SOAP Over HTTP和SOAP Over JMS。
2、JMS體系結構元素
JMS提供者(JMS provider):JMS接口的實現。
JMS客戶:生產或消費基于消息的Java的應用程序或對象。
JMS生產者:創建并發送消息的JMS客戶。
JMS消費者:接收消息的JMS客戶。
JMS消息:包括可以在JMS客戶之間傳遞的數據的對象
JMS隊列:一個容納那些被發送的等待閱讀的消息的區域。隊列暗示,這些消息將按照順序發送。一旦一個消息被閱讀,該消息將被從隊列中移走。
JMS主題:一種支持發送消息給多個訂閱者的機制。
JMS提供商:JMS規范實現廠商
JMS管理對象:預先配置好的用于JMS客戶端的JMS對象。如:ConnectionFactory--這個對象用于客戶端來創建和提供商的連接,Destination--這個對象用于客戶端來指定發送消息的目的地(Queue或 Topic),也是接收消息的來源。被管理對象被管理員放置在JNDI命名空間。JMS客戶端通常在它的文檔中注上它要求的JMS被管理對象和這些對象的JNDI名字應當如何提供給它。
JMS Domain:JMS定義了兩種域模型,一種是PTP(point-to-point)即點對點消息傳輸模型,一種是pub/sub(publish-subscribe)即發布訂閱模型。
3、JMS接口
JMS支持兩種消息類型PTP和Pub/Sub,分別稱作:PTP Domain 和Pub/Sub Domain,這兩種接口都繼承統一的JMS父接口。JMS基于一系列通用的消息概念,每個JMS消息域—PTP和Pub/Sub—也為這些概念定義了各自的接口集。JMS客戶端程序員使用這些接口來創建他們的客戶端程序。JMS主要接口如下:
Destination:消息的目的地,封裝了消息目的地標識的被管理對象。
Session:一個用于發送和接收消息的單線程上下文。
MessageProducer(生產者): 由Session對象創建的用來發送消息的對象。
MessageConsumer(消費者):由Session對象創建的用來接收消息的對象。
接口之間的關系如下:
(JMS應用)發送端的標準流程是:創建連接工廠>創建連接>創建session>創建發送者>創建消息體>發送消息到Destination(queue或topic)。
接收端的標準流程是:創建連接工廠>創建連接>創建session>創建接收者>創建消息監聽器監聽某Destination的消息>獲取消息并執行業務邏輯
4、JMS消息
消息是JMS中的一種類型對象,由兩部分組成:消息頭和消息體(或分三部分:消息頭、屬性、消息體)。消息頭由路由信息以及有關該消息的元數據組成。消息體則攜帶著應用程序的數據或有效負載。
1)消息頭(Header):消息頭包含消息的識別信息和路由信息,標準的JMS消息頭包含以下屬性:
JMSDestination:消息發送的目的地。
JMSDeliveryMode:傳遞模式,有兩種模式: PERSISTENT和NON_PERSISTENT,PERSISTENT表示該消息一定要被送到目的地,否則會導致應用錯誤。NON_PERSISTENT表示偶然丟失該消息是被允許的,這兩種模式使開發者可以在消息傳遞的可靠性和吞吐量之間找到平衡點。標記為NON_PERSISTENT的消息最多投遞一次,而標記為PERSISTENT的消息將使用暫存后再轉送的機理投遞。如果一個JMS服務離線,那么持久性消息不會丟失但是得等到這個服務恢復聯機時才會被傳遞。所以默認的消息傳遞方式是非持久性的。
JMSExpiration:消息過期時間,等于QueueSender的send方法中的timeToLive值或TopicPublisher的publish方法中的timeToLive值加上發送時刻的GMT時間值。如果timeToLive值等于零,則JMSExpiration被設為零,表示該消息永不過期。如果發送后,在消息過期時間之后消息還沒有被發送到目的地,則該消息被清除。
JMSPriority:消息優先級,從0-9 十個級別,0-4是普通消息,5-9是加急消息。JMS不要求JMS Provider嚴格按照這十個優先級發送消息,但必須保證加急消息要先于普通消息到達。
JMSMessageID:唯一識別每個消息的標識,由JMS Provider產生。
JMSTimestamp:一個消息被提交給JMS Provider到消息被發出的時間。
JMSCorrelationID:用來連接到另外一個消息,典型的應用是在回復消息中連接到原消息。
JMSReplyTo:提供本消息回復消息的目的地址。
JMSType:消息類型的識別符。
JMSRedelivered:如果一個客戶端收到一個設置了JMSRedelivered屬性的消息,則表示可能該客戶端曾經在早些時候收到過該消息,但并沒有簽收(acknowledged)。
除了消息頭中定義好的標準屬性外,JMS提供一種機制增加新屬性到消息頭中,這種新屬性包含以下幾種:應用需要用到的屬性、消息頭中原有的一些可選屬性、JMS Provider需要用到的屬性。
2)消息體:JMS API定義了5種消息體格式,也叫消息類型,你可以使用不同形式發送接收數據并可以兼容現有的消息格式,下面描述這5種類型:
TextMessage:java.lang.String對象,如xml文件內容
MapMessage:名/值對的集合,名是String對象,值類型可以是Java任何基本類型
BytesMessage:字節流
StreamMessage:Java中的輸入輸出流
ObjectMessage:Java中的可序列化對象
Message:沒有消息體,只有消息頭和屬性
3)消息可靠性
在上面談及消息體格式定義中,有個字段JMSDeliveryMode用來表示該消息發送后,JMS提供商應該怎么處理消息。PERSISTENT(持久化)的消息在JMS服務器中持久化。接收端如果采用點對點的queue方式或者Durable Subscription(持久訂閱者)方式,那么消息可保證只且只有一次被成功接收。NON_PERSISTENT(非持久化)的消息在JMS服務器關閉或宕機時,消息丟失。根據發送端和接收端采用的方式,列出如下可靠性表格,以作參考。
注意:以下的可靠性不包括JMS服務器由于資源關系,造成的消息不能持久化等因素引起的不可靠(該類不可靠應該是JMS提供商或硬件引起的的資源和處理能力的極限問題,應該由管理人員解決)。也不包括消息由于超時時間造成的銷毀丟失。
消息發送端 消息接收端 可靠性及因素
PERSISTENT queue receiver/durable subscriber 消費一次且僅消費一次。可靠性最好,但是占用服務器資源比較多。
PERSISTENT non-durable subscriber 最多消費一次。這是由于non-durable subscriber決定的,如果消費端宕機或其他問題導致與JMS服務器斷開連接,等下次再聯上JMS服務器時消息不保留。
NON_PERSISTENT queue receiver/durable subscriber 最多消費一次。這是由于服務器的宕機會造成消息丟失
NON_PERSISTENT non-durable subscriber 最多消費一次。這是由于服務器的宕機造成消息丟失,也可能是由于non-durable subscriber的性質所決定
4)消息的優先級
雖然JMS規范并不需要JMS供應商實現消息的優先級路線,但是它需要遞送加快的消息優先于普通級別的消息。JMS定義了從0到9的優先級路線級別,0是最低的優先級而9則是最高的。更特殊的是0到4是正常優先級的變化幅度,而5到9是加快的優先級的變化幅度。舉例來說:
topicPublisher.publish (message, DeliveryMode.PERSISTENT, 8, 10000); //Pub-Sub
或 queueSender.send(message,DeliveryMode.PERSISTENT, 8, 10000);//P2P
這個代碼片斷,有兩種消息模型,映射遞送方式是持久的,優先級為加快型,生存周期是10000 (以毫秒度量)。如果生存周期設置為零,這則消息將永遠不會過期。當消息需要時間限制否則將使其無效時,設置生存周期是有用的。
5)消息的通知確認
在客戶端接收了消息之后,JMS服務怎樣有效確認消息是否已經被客戶端接收呢?
Session session=connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
這段代碼創建一個非事務性的session,并采用auto_acknowledge方式通知JMS服務器。如果采用事務性session時,通知會伴隨session的commit/rollback同時發送通知。在我們采用非事務session時,有三種通知方式。
通知方式 效果
DUPS_OK_ACKNOWLEDGE session 延遲通知。如果JMS服務器宕機,會造成重復消息的情況。程序必須保證處理重復消息而不引起程序邏輯的混亂。
AUTO_ACKNOWLEDGE 當receive或MessageListener方法成功返回后自動通知。
CLIENT_ACKNOWLEDGE 客戶端調用消息的acknowledge方法通知
5、PTP模型
點對點(Point- to-Point)消息傳送使用的目標是隊列。通過使用隊列,消息可以被異步或同步地發送和接收。每一條到達隊列的消息將會被投遞到單獨一個消費者一次,并且只有一次。這就好像兩個人之間的郵件發送。消費者可以通過MessageConsumer.receive()方法同步地接收消息或使用 MessageConsumer.setMessageListener()方法注冊一個MessageListener實現來異步地接收消息。隊列保存所有的消息直到它們被投遞出去或過期。
JMS PTP模型中的主要概念和對象:
Queue:由JMS Provider管理,隊列由隊列名識別,客戶端可以通過JNDI接口用隊列名得到一個隊列對象。
TemporaryQueue:由QueueConnection創建,而且只能由創建它的QueueConnection使用。
QueueConnectionFactory:客戶端用QueueConnectionFactory創建QueueConnection對象。
QueueConnection:一個到JMS PTP provider的連接,客戶端可以用QueueConnection創建QueueSession來發送和接收消息。
QueueSession:提供一些方法創建QueueReceiver 、QueueSender、QueueBrowser和TemporaryQueue。如果在QueueSession關閉時,有一些消息已經被收到,但還沒有被簽收(acknowledged),那么,當接收者下次連接到相同的隊列時,這些消息還會被再次接收。
QueueReceiver:客戶端用QueueReceiver接收隊列中的消息,如果用戶在QueueReceiver中設定了消息選擇條件,那么不符合條件的消息會留在隊列中,不會被接收到。
QueueSender:客戶端用QueueSender發送消息到隊列。
QueueBrowser:客戶端可以QueueBrowser瀏覽隊列中的消息,但不會收走消息。
QueueRequestor:JMS提供QueueRequestor類簡化消息的收發過程。QueueRequestor的構造函數有兩個參數:QueueSession和queue,QueueRequestor通過創建一個臨時隊列來完成最終的收發消息請求。
可靠性(Reliability):隊列可以長久地保存消息直到接收者收到消息。接收者不需要因為擔心消息會丟失而時刻和隊列保持激活的連接狀態,充分體現了異步傳輸模式的優勢。
可以看到,一個或多個生產者發送消息,消息m2先抵達了queue,然后m1也發出了,并一同存在于一個先進先出的queue里面。消費者也存在一個或多個,對queue里的消息進行消費。但一個消息只會被的一個消費者消費且僅消費一次。
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):當所有的消息必須被接收,則用持久訂閱模式。當丟失消息能夠被容忍,則用非持久訂閱模式。
在pub/sub消息模型中,消息被廣播給所有訂閱者。訂閱者可以同步接收消息也可以異步接收消息,消息的同步接收是指客戶端主動去接收消息,消息的異步接收是指當消息到達時,主動通知客戶端。
使用JMeter測試JMS
JMeter是Apache開發的一款小巧易用的開源性能測試工具,由java語言開發。JMeter不僅免費開源而且功能強大、易于擴展,如果有一定Java開發基礎的話還可以在JMeter上做擴展開發新的插件等,幾乎能滿足各種性能測試需求。JMeter中使用Sampler元件(取樣器)來模擬各種的類型的請求數據格式,類似于LR中的協議(比LR中的協議概念更廣),如:http、ftp、soap、tcp等等。JMeter中支持的JMS Point-to Point、JMS Publisher和JMS Subscriber分別用于發送JMS的PTP消息和PUB/SUB消息,因此可以選擇使用JMeter來測試JMS。
MOM(消息中間件)作為消息數據交換的平臺,也是影響應用執行效率的潛在環節。在Java程序中,是通過JMS與MOM進行交互的。作為Java實現的性能測試工具JMeter也能使用JMS對應用的消息交換和相關的數據處理能力進行測試。在整個測試過程中,JMeter測試的重點是消息的產生者和消費者的能力,而不是MOM本身。JMeter雖然能使用JMS對MOM進行測試,但是它本身并沒有提供JMS需要使用的包(實現類)。因此在使用JMeter測試JMS時需要使用到具體的MOM的相關jar包。以下結合流行的開源消息中間件ActiveMQ來演示如何使用JMeter來實現對JMS的測試。
1、安裝并啟動ActiveMQ服務
2、測試前的準備
使用JMeter進行壓力測試時,所有的JMeter依賴的包需要復制到%JMETER_HOME%/lib目錄下。對于ActiveMQ來說,就是復制%ACTIVEMQ_HOME%/lib目錄下jar包,可根據實際情況來考慮是否復制。JMeter在測試時使用了JNDI,為了提供JNDI提供者的信息,需要提供jndi.properties。同時需要將jndi.properties放到JMeter的%JMETER_HOME%/lib和%JMETER_HOME%/bin目錄中,還需要將jndi.properties與%JMETER_HOME%/bin目錄下的ApacheJMeter.jar打包在一起。對于ActiveMQ,jndi.properties的演示內容如下:
1 #java.naming.factory.initial = org.activemq.jndi.ActiveMQInitialContextFactory 2 java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory 3 java.naming.provider.url = tcp://localhost:61616 4 5 #指定connectionFactory的jndi名字,多個名字之間可以逗號分隔。 6 #以下為例: 7 #對于topic,使用(TopicConnectionFactory)context.lookup("connectionFactry") 8 #對于queue,(QueueConnectionFactory)context.lookup("connectionFactory") 9 connectionFactoryNames = connectionFactory 10 11 #注冊queue,格式: 12 #queue.[jndiName] = [physicalName] 13 #使用時:(Queue)context.lookup("jndiName"),此處是MyQueue 14 queue.MyQueue = example.MyQueue 15 16 #注冊topic,格式: 17 # topic.[jndiName] = [physicalName] 18 #使用時:(Topic)context.lookup("jndiName"),此處是MyTopic 19 topic.MyTopic = example.MyTopic |
3、測試JMS的PTP模型
對于點對點模型,JMeter只提供了一種Sampler:JMS Point-to-Point。如圖所示建立測試計劃:
QueueConnection Factory:連接工廠,輸入jndi配置文件中配置的connectionFactory
JNDI name Request queue:請求隊列名,輸入jndi配置文件中配置的MyQueue
JNDI name Receive queue:接收隊列名,輸入jndi配置文件中配置的MyQueue
Content:消息內容,比如輸入:this is a test
Initial Context Factory:輸入org.apache.activemq.jndi.ActiveMQInitialContextFactory
Provider URL:提供者URL,即安裝的ActiveMQ的服務地址tcp://yourIP:61616
運行調試時通過監視器元件查看是否發送成功,如下說明發送成功:
posted on 2014-10-30 10:18 順其自然EVO 閱讀(437) 評論(0) 編輯 收藏 所屬分類: 測試學習專欄