ActiveMQ簡介

五柳-先生發表於2015-08-27

ActiveMQ簡介

1.  什麼是ActiveMQ

ActiveMQ是一種開源的,實現了JMS1.1規範的,面向訊息(MOM)的中介軟體,為應用程式提供高效的、可擴充套件的、穩定的和安全的企業級訊息通訊。ActiveMQ使用Apache提供的授權,任何人都可以對其實現程式碼進行修改。

ActiveMQ的設計目標是提供標準的,面向訊息的,能夠跨越多語言和多系統的應用整合訊息通訊中介軟體。ActiveMQ實現了JMS標準並提供了很多附加的特性。這些附加的特性包括,JMX管理(java Management Extensions,即java管理擴充套件),主從管理(master/salve,這是叢集模式的一種,主要體現在可靠性方面,當主中介(代理)出現故障,那麼從代理會替代主代理的位置,不至於使訊息系統癱瘓)、訊息組通訊(同一組的訊息,僅會提交給一個客戶進行處理)、有序訊息管理(確保訊息能夠按照傳送的次序被接受者接收)。訊息優先順序(優先順序高的訊息先被投遞和處理)、訂閱訊息的延遲接收(訂閱訊息在釋出時,如果訂閱者沒有開啟連線,那麼當訂閱者開啟連線時,訊息中介將會向其提交之前的,其未處理的訊息)、接收者處理過慢(可以使用動態負載平衡,將多數訊息提交到處理快的接收者,這主要是對PTP訊息所說)、虛擬接收者(降低與中介的連線數目)、成熟的訊息持久化技術(部分訊息需要持久化到資料庫或檔案系統中,當中介崩潰時,資訊不會丟失)、支援遊標操作(可以處理大訊息)、支援訊息的轉換、通過使用Apache的Camel可以支援EIP、使用映象佇列的形式輕鬆的對訊息佇列進行監控等。

2.  ActiveMQ 特性

支援JMS規範:ActiveMQ完全實現了JMS1.1規範。

JMS規範提供了同步訊息和非同步訊息投遞方式、有且僅有一次投遞語義(指訊息的接收者對一條訊息必須接收到一次,並且僅有一次)、訂閱訊息持久接收等。如果僅使用JMS規範,表明無論您使用的是哪家廠商的訊息代理,都不會影響到您的程式。

連線方式的多樣化:ActiveMQ提供了廣泛的連線模式,包括HTTP/S、JGroups、JXTA、muticast、SSL、TCP、UDP、XMPP等。提供瞭如此多的連線模式表明了ActiveMQ具有較高的靈活性。

可插入式的持久化和安全:ActiveMQ提供了多種持久化方案,您可以根據實際需要進行選擇。同時,也提供了完整的客戶授權模式。

使用Java建立訊息應用程式:最常見的使用ActiveMQ的方式就是使用Java程式來傳送和接收訊息。

與其他的Java容器緊密整合:ActiveMQ提供了和其它流行的Java容器的結合,包括Apache Geronimo、Apache Tomcat、JBoss、Jetty等。

客戶端API:ActiveMQ提供了多種客戶端可訪問的API,包括Java、C/C++,.NET,Perl、PHP、Python、Ruby等。當然,ActiveMQ中介必須執行在Java虛擬機器中,但是使用它的客戶端可以使用其他的語言來實現。

中介叢集:多個ActiveMQ中介可以一起協同工作,來完成某項複雜的工作,這被稱為網路型中介(network of brokers),這種型別的中介將會支援多種拓撲型別。

3.  為什麼使用ActiveMQ

在設計分散式應用程式時,應用程式間的耦合(或稱整合)方式很重要。耦合意味著兩個或者多個應用程式或系統的相互依賴關係。一種簡單的方式是在所有的應用程式中從架構上設計他們與其他應用程式間的交叉實現。這樣必然導致,一個應用程式的改變,直接導致另一個應用程式的改變。按照這種方式整合的應用是一種緊耦合的應用。一個應用的改變不會影響到其他應用的整合方式被稱為是鬆耦合的整合方式。簡單的說,鬆耦合應用程式整合能夠更容易的處理不可預見的應用變化。

像COM、CORBA、DCE和EJB等應用技術使用RPC(Remote Procedural Calls,即遠端過程呼叫)屬於緊耦合技術。使用RPC,一個應用程式呼叫另一個應用程式,呼叫者必須阻塞,直到被呼叫者執行結束返回結果資訊為止。下圖給出了這種緊耦合技術的描述:

 

許多系統架構使用RPC,並且獲得了巨大的成功,但是,緊耦合的架構有著天生的缺陷。首先,這種架構將會造成系統維護管理上的巨大消費,因為,即使是很小的改動,很可能會波及到整個系統。其次,由於呼叫者必須阻塞式的等待被呼叫者返回,如果被呼叫者處理過程複雜,將會嚴重影響呼叫者的執行效率和資源使用率。此外,如果呼叫失敗,整個架構即失敗。

下圖給出一種鬆耦合的方式,進行架構設計:

應用程式1向訊息中介(MOM)傳送一條訊息,很可能一段時間之後,應用程式2呼叫MOM來收取訊息。任何一個應用程式都不知道對方是否存在也不需要阻塞等待。這種通訊方式大大縮減了維護開銷,因為對於一個應用程式的修改,會對其他應用程式影響極小。

ActiveMQ就是採用了上面提到的鬆耦合方式,因此,我們經常說應用程式傳送訊息僅僅是觸發後忘卻。應用程式將訊息傳送給ActiveMQ而並不關心什麼時間以何種方式訊息投遞給接收者。同樣的,訊息接收者也不會關心訊息來源於哪裡和訊息是怎樣投遞給ActiveMQ的。對於多語言編寫的複雜應用環境中,允許客戶端使用不同的程式語言甚至不同的訊息包裝協議。ActiveMQ作為訊息的中介軟體,允許複雜的多語言應用程式以一種一步的方式整合和互動。所以說,ActiveMQ是一種好的,提供鬆散耦合的,能夠為多語言交叉應用提供整合的中介軟體。

4.  什麼情況下使用ActiveMQ

正如前面提到的,緊耦合應用系統存在許多問題,但是,要將緊耦合系統重構成鬆耦合系統是一件值得但比較繁瑣的事情。使用鬆耦合的主要優勢體現在將同步改為非同步。使用非同步通訊,應用程式將從接收者反饋的等待中解放出來,其他的任務可以得到執行,這樣提高了應用程式的效率。

只要是兩個應用程式間需要通訊的情況,都可以考慮使用JMS,不論這種通訊是在本地的(就是通訊的兩個應用程式在同一臺主機上),還是分佈在不同機器上。儘管是在同一個主機上的兩個應用程式需要通訊也可以使用ActiveMQ。ActiveMQ可以確保訊息投遞成功並採用非同步方式通訊。

多個需要通訊的應用程式在同一個機器上的情況下,您可以考慮在執行機上獨立執行ActiveMQ或者將ActiveMQ嵌入到Java應用服務中。無論採用哪種方式,都可以確保應用程式能夠傳送和接收訊息。您可以選擇訂閱模式(pub/sub)或者採用PTP(point to point)模式,這兩種模式都無需等待執行反饋資訊。每一個應用程式都可以簡單的將訊息傳送給ActiveMQ,然後繼續做其他的工作;應用程式無需阻塞式等待訊息的返回。

對於分佈在多臺主機上的應用程式來說,可以使用多種佈置策略。主要包括單一ActiveMQ例項和多ActiveMQ例項。單一ActiveMQ例項是一個簡單解決方案。所有的應用程式都向同一個ActiveMQ中介傳送和接收訊息,這與上面提到的單機多服務雷同。單一的ActiveMQ可以佈置到一臺單獨的主機上,也可以和其中的一些服務佈置在一起。重要的是,所有的應用必須能夠直接與ActiveMQ中介進行互動,所以,你必須考慮到你的網路設計。

第二種情況比較複雜,但是有ActiveMQ來負責遠端通訊,而不是應用程式自身。在這種場景下,每一個應用程式都會例項化一個ActiveMQ(無論是嵌入式的還是獨立式的),應用程式從其本地的ActiveMQ傳送和接收訊息。之後這些ActiveMQ例項將會以一種聯合的方式協同工作。訊息將會基於每一個應用的要求在多個ActiveMQ中介間傳遞到遠端的處理者。在ActiveMQ中,這種模式被稱為netWork of brokers。採用這種模式對於處理大量的ActiveMQ訊息是可行的,但是,我們往往需要減輕網路拓撲的複雜性,這樣直接將訊息投遞到遠端接收者的ActiveMQ是不可行的。在後一種情況下,不同的協議使用可以使ActiveMQ更輕鬆的傳遞訊息。

5. ActiveMQ傳輸效率

計算機環境

CPU:Intel(R) Cpu G530 @ 2.40GHz 2.40 Memory:2GB HD:希捷 ST3500620AS OS:window xp Service Pack 3

 

   傳送10萬條長度為25的訊息耗時6~7秒鐘, cpu佔用量很大。

   如果持續傳送不接受的話,伺服器承受到30萬時容易卡住傳送達到26秒之多

   一次性接收所有的訊息50萬,cpu佔用100%佔用時間50s左右,可以全部接收。

   接收完成後在繼續傳送10萬訊息佔用時間6~7s

  在一次性傳送50萬訊息時出現問題

INFO | Usage Manager Memory Limit (524288000) reached on queue://FirstQueue. Producers will be throttled to the rate at which messages are removed from this destination to prevent flooding it. See

http://activemq.apache.org/producer-flow-control.html for more info

 

在網上找原因說是配置了傳送限制,修改xml 執行時間是53s 的樣子

 

繼續傳送50萬,一分50秒

 

在傳送50萬

 

在傳送50萬2分多鐘的樣子

 

 試著接收這200萬訊息可以成功,但時間很長。

  修改xml後在接受訊息的同時傳送10萬訊息,

 

  一次傳送100萬耗時4分左右的樣子

 

接收方也可以全部接收。

  模擬伺服器斷電,非永續性模式時沒有被消費的訊息不會繼續消費,全部丟失

程式會報一個連線關閉異常停止執行,繼續啟動伺服器執行程式,不會接收任何訊息。

         模擬伺服器斷電,永續性模式時沒有被消費的訊息會繼續消費

定義了訊息的永續性模式後,即使關閉了伺服器,程式也會報連線關閉異常,但再次啟動伺服器和程式後,接收方還能繼續原來的訊息再次接收。

總結

總體看來,在配置好xml的情況下,activemq對訊息傳輸上還是沒有問題的,傳送的訊息都可以全部接收,傳送多少條就接收多少條,準確度上還是有保證的,持久模式支援斷電續傳功能。雖然功能上沒有什麼問題但對cpu的佔用率就比較大了,傳送或接受訊息的時候都達到了100%,記憶體到不會很大。這跟自己使用機子有關係,配置好點的機子可能情況會好些。

6. ActiveMQ配置傳輸連線

ActiveMQ提供了廣泛的連線模式,包括HTTP/S、JGroups、JXTA、muticast、SSL、TCP、UDP、XMPP等。提供瞭如此多的連線模式表明了ActiveMQ具有較高的靈活性。

配置格式如下:

  <transportConnectors>

            <!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->

            <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&amp;wireformat.maxFrameSize=104857600"/>

            <transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&amp;wireformat.maxFrameSize=104857600"/>

            <transportConnector name="ssl" uri="ssl://0.0.0.0:61617?maximumConnections=1000&amp;wireformat.maxFrameSize=104857600"/>

            <transportConnector name="stomp" uri="stomp://0.0.0.0:61618?maximumConnections=1000&amp;wireformat.maxFrameSize=104857600"/>

            <transportConnector name="xmpp" uri="xmpp://0.0.0.0:61619?maximumConnections=1000&amp;wireformat.maxFrameSize=104857600"/>

        </transportConnectors>

生產者和消費著可以使用不同的傳輸協議來傳輸資訊。比如生產者用nio協議生產訊息,消費者用tcp協議接收訊息。

7. ActiveMQ配置網路連線

當應用到Broker的叢集時,Borker與Broker的通訊就用到了網路連線。

配置格式如下:

<networkConnectors>

<!-- 動態連線方式

<networkConnector name="default-nc" uri="multicast://default"

                   dynamicOnly="true" networkTTL="3" prefetchSize="1" decreaseNetworkConsumerPriority="true"

         /> -->

         <!-- 靜態連線方式 <networkConnector name="host1 and host2" uri="static://(tcp://host1:61616,tcp://host2:61616)"/> -->

</networkConnectors>

 

8.  ActiveMQ持久化儲存模式

ActiveMq主要實現瞭如下幾種儲存:

1.4.1.   AMQ訊息儲存—預設的訊息儲存

  它是一種基於檔案儲存的訊息資料庫並且不依賴第三方資料庫。配置如下

<amqPersistenceAdapter directory="${activemq.base}/data" maxFileLength="32mb"/>

 

1.4.2.   KahaDB 訊息儲存—提供容量的提升和恢復能力

  它是一種新的訊息儲存機制,配置如下

<kahaDB directory="${activemq.data}/kahadb" />

 

1.4.3.   JDBC 訊息儲存—訊息基於JDBC儲存

<persistenceAdapter>

<jdbcPersistenceAdapter  dataSource="#mysql-ds"/>

</persistenceAdapter>

<bean id="mysql-ds" class="org.apache.commons.dbcp.BasicDataSource"

                            destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/>

                            <property name="url" value="jdbc:mysql://localhost/activemq?relaxAutoCommit=true"/>

                            <property name="username" value="activemq"/> <property name="password" value="activemq"/>

                            <property name="maxActive" value="200"/> <property name="poolPreparedStatements"

                            value="true"/>

                   </bean>

 

1.4.4.   Memory 訊息儲存—基於內容的訊息儲存

  ActiveMQ支援將訊息儲存到記憶體中,這種情況沒有動態的快取存在。

  這種情況的配置很簡單,只要將Broker的“prsistent” 屬性設定為“false”即可。

1.   ActiveMQ負載均衡

ActiveMQ可以實現多個mq之間進行路由,假設有兩個mq,分別為brokerA和brokerB,當有一條訊息傳送到brokerA的佇列test中,有一個客戶端連線到brokerB上,並且要求獲取test佇列的訊息時,brokerA中佇列test的訊息就會路由到brokerB上,反之brokerB的訊息也會路由到brokerA。分靜態和動態兩種配置方法,見《6   activemq的網路連線》。下面給出動態配置:

<networkConnectors>

            <networkConnector uri="multicast://default" />

</networkConnectors>

 <transportConnectors>

            <!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->

            <transportConnector name="openwire" uri="tcp://0.0.0.0:61618" discoveryUri="multicast://default" />

        </transportConnectors>

2.   ActiveMQ主從配置

Master-Slave模式分為三類:Pure Master Slave、Shared File System Master Slave和JDBC Master Slave。以上三種方式的叢集都不支援負載均衡,但可以解決單點故障的問題,以保證訊息服務的可靠性。

2.1.  PureMaster Slave

    需要兩個Broker,一個作為Master,另一個作為Slave,執行時,Slave通過網路實時從Master處複製資料,同時,如果Slave和Master失去連線,Slave就會自動升級為Master,繼續為客戶端提供訊息服務,這種方式的Slave只能有一個。模型如圖所示:

 

這種方式的主備不需要對Master Broker做特殊的配置,只要在Slave Broker中指定他的Master就可以了,指定Master有兩種方式,最簡單的配置就是在broker節點中新增masterConnectorURI=”tcp://localhost:61616″即可,還有一種方式就是新增一個services節點,可以指定連線的使用者名稱和密碼,配置如下:

<services>

  <masterConnector remoteURI= "tcp://localhost:61616" userName="system" password="manager"/>

</services>

 

2.2.  SharedFile System Master Slave

        SharedFile System Master Slave就是利用共享檔案系統做ActiveMQ叢集,是基於ActiveMQ的預設資料庫kahaDB完成的,kahaDB的底層是檔案系統。這種方式的叢集,Slave的個數沒有限制,哪個ActiveMQ例項先獲取共享檔案的鎖,那個例項就是Master,其它的ActiveMQ例項就是Slave,噹噹前的Master失效,其它的Slave就會去競爭共享檔案鎖,誰競爭到了誰就是Master。這種模式的好處就是當Master失效時不用手動去配置,只要有足夠多的Slave。如果各個ActiveMQ例項需要執行在不同的機器,就需要用到分散式檔案系統了。模式如圖所示:

 

2.3.  JDBCMaster Slave

        JDBCMaster Slave模式和Shared File Sysytem Master Slave模式的原理是一樣的,只是把共享檔案系統換成了共享資料庫。我們只需在所有的ActiveMQ的主配置檔案中新增資料來源,所有的資料來源都指向同一個資料庫,然後修改持久化介面卡。這種方式的叢集相對Shared File System Master Slave更加簡單,更加容易地進行分散式部署,但是如果資料庫失效,那麼所有的ActiveMQ例項都將失效。

3.   ActiveMQ攔截器使用

在ActiveMQ中使用攔截器和過濾器的使用多采用外掛的形式實現,繼承BrokerFilter實現BrokerPlugin介面類。BrokerFilter實質一個實現Broker介面的類。

3.1.  日誌攔截

日誌攔截器是Broker的一個攔截器,預設的日誌級別為INFO。你如你想改變日誌的級別。這個日誌攔截器支援Commons-log和Log4j兩種日誌。

<plugins>

      <loggingBrokerPlugin logAll="true" logConnectionEvents="false"/>

    </plugins>

部分引數如下:

屬性名稱

預設值

描述

logAll

false

記錄所有事件的日誌

logMessageEvents

false

記錄訊息事件日誌

logConnectionEvents

True

記錄連線事件日誌

logTransactionEvents

false

記錄訊息事務事件日誌

logConsumerEvents

false

記錄訊息消費者事件日誌

logProducerEvents

false

記錄訊息生產者事件日誌

logInternalEvents

false

 

3.2.   統計攔截器

StatisticsPlugin外掛被用作檢測Broker中統計的外掛。注意訊息必須包含replyTo的訊息頭,如果是在JMS那麼需要採用jmsReplyTo訊息頭,否則訊息將被統計忽略。ReplyTo訊息頭包含了你想檢查統計的訊息。統計訊息是一個MapMessage.

      檢查Broker的資訊,僅僅需要一個名稱為ActiveMQ.Statistics.Broker並且有一個replyTo的訊息頭的Destination。為了檢測所有destination,你需要一個名稱為ActiveMQ.Statistics.Destination.<destination-name>或者ActiveMQ.Statistics.Destination.<wildcard-expression>並且有一個replyTo的訊息頭。如果許多Destination匹配相關的模糊匹配表示式,那麼統計的訊息將被髮送到replyTo的Destination.

<plugins>

      <statisticsBrokerPlugin/>

</plugins>

 

 

 

 

4.   ActiveMQ安全配置

ActiveMQ也可以對各個主題和佇列設定使用者名稱和密碼,配置如下:

<plugins>

  <!-- Configure authentication; Username, passwords and groups -->

  <simpleAuthenticationPlugin>

      <users>

          <authenticationUser username="system" password="manager" groups="users,admins"/>

          <authenticationUser username="user" password="password" groups="users"/>

          <authenticationUser username="guest" password="password" groups="guests"/>

          <authenticationUser username="testUser" password="123456" groups="testGroup"/>

      </users>

  </simpleAuthenticationPlugin>

  <!--  Lets configure a destination based authorization mechanism -->

  <authorizationPlugin>

    <map>

      <authorizationMap>

        <authorizationEntries>

          <authorizationEntry queue="queue.group.uum" read="users" write="users" admin="users" />

          <authorizationEntry queue=">" read="admins" write="admins" admin="admins" />

          <authorizationEntry queue="USERS.>" read="users" write="users" admin="users" />

          <authorizationEntry queue="GUEST.>" read="guests" write="guests,users" admin="guests,users" />

          <authorizationEntry queue="TEST.Q" read="guests" write="guests" />

          <authorizationEntry queue="test" read=" testGroup " write=" testGroup " />

          <authorizationEntry topic=">" read="admins" write="admins" admin="admins" />

          <authorizationEntry topic="USERS.>" read="users" write="users" admin="users" />

          <authorizationEntry topic="GUEST.>" read="guests" write="guests,users" admin="guests,users" />

          <authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users ,testGroup" write="guests,users ,testGroup " admin="guests,users ,testGroup "/>

        </authorizationEntries>

      </authorizationMap>

    </map>

  </authorizationPlugin>

</plugins>

5.   ActiveMQ中NetWorkConnctor屬性

 

 

    <networkConnector name="bridge" uri="static://(tcp://host1:61616)"

                duplex="true" conduitSubscriptions="true"

                decreaseNetworkConsumerPriority="false" >

            </networkConnector>

 

屬性名稱

預設值

描述

Duplex

True

表示雙向可以通訊

ConduitSubscriptions

False

表示每個Consumer 上都會收到所有的傳送的訊息

DynamicOnly

false

訊息將被動態的轉接的在其他Broker的consumer上

PrefetchSize

1000

指定訊息的數量

ConduitSubscriptons

true

 

excludedDestinations

 

指定排除的地址

DynamiccallyincludedDestinations

 

包括的地址

StaticcallyincludedDestinations

 

靜態的包括訊息地址

DecreaseNetwordConsumerPriority

false

消費者優先權

NetworkTTl

1

 

 

6.   ActiveMQ訊息遊標

當producer 傳送的持久化訊息到達broker 之後,broker 首先會把它儲存在持

久儲存中。接下來,如果發現當前有活躍的 consumer,而且這個consumer 消費訊息的速度能跟上producer 生產訊息的速度,那麼ActiveMQ 會直接把訊息傳遞給 broker 內部跟這個consumer關聯的 dispatch(派遣、排程) queue;如果當前沒有活躍的 consumer或者 consumer 消費訊息的速度跟不上producer 生產訊息的速度,那麼 ActiveMQ 會使用Pending Message Cursors 儲存對訊息的引用。在需要的時候,Pending Message Cursors 把訊息引用傳遞給broker 內部跟這個consumer關聯的 dispatch queue。以下是兩種Pending (未解決)Message Cursors:

    VM Cursor。在記憶體中儲存訊息的引用。

    File Cursor。首先在記憶體中儲存訊息的引用,如果記憶體使用量達到上限, 那麼會把訊息引用儲存到臨時檔案中。

對於 topic,可以使用的pendingSubscriberPolicy 有vmCursor 和 fileCursor。可以使用的PendingDurableSubscriberMessageStoragePolicy 有 vmDurableCursor 和 fileDurableSubscriberCursor。以下是ActiveMQ 配置檔案 的一個例子:

Xml 程式碼

<destinationPolicy>

        <policyMap>

        <policyEntries>

                  <policyEntry     topic="org.apache.>">

                      <pendingSubscriberPolicy>

                          <vmCursor  />

                        </pendingSubscriberPolicy>

                       <PendingDurableSubscriberMessageStoragePolicy>

 

                           <vmDurableCursor/>

                       </PendingDurableSubscriberMessageStoragePolicy>

 

                 </policyEntry>

           </policyEntries>

        </policyMap>

    </destinationPolicy>

 

  對於 queue,可以使用的pendingQueuePolicy 有vmQueueCursor 和 fileQueueCursor。以下是ActiveMQ 配置檔案的一個例子:

<destinationPolicy>

        <policyMap>

             <policyEntries>

                  <policyEntry     queue="org.apache.>">

                       <pendingQueuePolicy>

                            <vmQueueCursor  />

                       </pendingQueuePolicy>

                 </policyEntry>

            </policyEntries>

         </policyMap>

    </destinationPolicy>

7.   ActiveMQ嚴格排程策略

有時候需要保證不同的 topic consumer 以相同的順序接收訊息。通常

ActiveMQ 會保證 topic consumer 以相同的順序接收來自同一個producer 的訊息。

然而,由於多執行緒和非同步處理,不同的 topic consumer可能會以不同的順序接收

來自不同producer 的訊息。例如有兩個producer,分別是P 和Q。差不多是同一

時間內,P 傳送了P1、P2 和P3 三個訊息;Q 傳送了Q1 和Q2 兩個訊息。兩個不同

的consumer可能會以以下順序接收到訊息:

        consumer1: P1 P2 Q1 P3 Q2

        consumer2: P1 Q1 Q2 P2 P3

        Strict order dispatch policy 會保證每個 topic consumer會以相同的

順序接收訊息,代價是效能上的損失。以下是採用了strict order dispatch policy

後,兩個不同的 consumer可能以以下的順序接收訊息:

        consumer1: P1 P2 Q1 P3 Q2

        consumer2: P1 P2 Q1 P3 Q2

      以下是ActiveMQ 配置檔案的一個例子:

   <destinationPolicy>

         <policyMap>

             <policyEntries>

                <policyEntry   topic="FOO.>">

                     <dispatchPolicy>

                        <strictOrderDispatchPolicy  />

                      </dispatchPolicy>

                  </policyEntry>

             </policyEntries>

        </policyMap>

   </destinationPolicy>

 

8.   ActiveMQ輪轉排程策略

介紹過 ActiveMQ 的prefetch(預讀取)機制,ActiveMQ 的預設引數是針對處理大量訊息時的高效能和高吞吐量而設定的。所以預設的 prefetch引數比較大,而且預設

的dispatch policies 會嘗試儘可能快的填滿 prefetch緩衝。然而在有些情況下,

例如只有少量的訊息而且單個訊息的處理時間比較長,那麼在預設的 prefetch和

dispatch policies下,這些少量的訊息總是傾向於被分發到個別的consumer 上。

這樣就會因為負載的不均衡分配而導致處理時間的增加。

       Round robin dispatch policy 會嘗試平均分發訊息,以下是 ActiveMQ配

置檔案的一個例子:

<destinationPolicy>     

      <policyMap>     

         <policyEntries>     

             <policyEntry  topic="FOO.>">     

                  <dispatchPolicy>     

                     <roundRobinDispatchPolicy  />     

                </dispatchPolicy>     

             </policyEntry>     

          </policyEntries>     

   </policyMap>     

</destinationPolicy>

 

9.   ActiveMQ Async Sends  

Acivemq 支援非同步和同步傳送訊息。在 ActiveMQ4.0 以上,所有的非同步或同步對

於 Consumer 來說是變得可配置了。預設是在 ConnectionFactory、Connection、

Connection URI等方面配置對於一個基於 Destination  的Consumer來說。

眾所周之,如果你想傳遞給 Slow Consumer 那麼你可能使用非同步的訊息傳遞,但是對於 Fast Consumer 你可能使用同步傳送訊息。(這樣可以避免同步和上下文切換額外的增加Queue 堵塞花費。如果對於一個 Slow Consumer,你使用同步傳送訊息可能出現Producer 堵塞等顯現。

ActiveMQ預設設定 dispatcheAsync=true是最好的效能設定。如果你處理的是

Slow Consumer 則使用 dispatcheAsync=true,反之,那你使用的是 Fast Consumer則使用dispatcheAsync=false。

用Connection URI 來配置Async如下:

ActiveMQConnectionFactory("tcp://locahost:61616?jms.useAsyncSend=true");

用ConnectionFactory 配置Async如下:

((ActiveMQConnectionFactory)connectionFactory).setUseAsyncSend(true);

用Connection 配置Async 如下:

((ActiveMQConnection)connection).setUseAsyncSend(true);

 

10.         ActiveMQ預設支援批量確認訊息

ActiveMQ預設支援批量確認訊息。由於批量確認會提高效能,因此這是預設的確認方式。如果希望在應用程式中禁止經過優化的確認方式,那麼可以採用如下方法:

cf = new ActiveMQConnectionFactory ("tcp://locahost:61616?jms.optimizeAcknowledge=false"); 

((ActiveMQConnectionFactory)connectionFactory).setOptimizeAcknowledge(false);   ((ActiveMQConnection)connection).setOptimizeAcknowledge(false); 

 

11.         ActiveMQ訊息型別

(一)Blob Message

(二)Advisory Message

(三)ActiveMQ Stream

(四)Transformer message

(五)TextMessage

(六)MapMessage

(七)BytesMessage

(八)StreamMessage

(九)ObjectMessage

(十)Message

12.         ActiveMQ  destination

12.1.     ActiveMQ的混合傳送模式

允許一個虛擬的destination代表多個destinations,多個destination之間用“,”分割。

Java程式碼:

Queue queue = new ActiveMQQueue("USERS.First,USERS.Sconder");

如果需要不同型別的destination,需要加上字首queue:// 或topic://

Queue queue = new ActiveMQQueue("USERS.First,USERS.Sconder,topic://USERS.topic1");

配置如下:

<amq:destinationInterceptors>

          <amq:virtualDestinationInterceptor>

          <amq:virtualDestinations>

          <amq:compositeQueue name="MY.QUEUE.A">

           <amq:forwardTo>

             <amq:queue physicalName="MY.QUEUE.B"></amq:queue>

             <amq:topic physicalName="MY.TOPIC.A"></amq:topic>

           </amq:forwardTo>

          </amq:compositeQueue>

          <amq:virtualTopic/>

          </amq:virtualDestinations>

          </amq:virtualDestinationInterceptor>

        </amq:destinationInterceptors>

 

12.2.     ActiveMQ的接收Mirrored模式

每個 queue 中的訊息只能被一個consumer 消費。然而,有時候你可能希望能

夠監視生產者和消費者之間的訊息流。你可以通過使用Virtual Destinations 來

建立一個virtual queue 來把訊息轉發到多個 queues 中。但是 為系統中每個

queue 都進行如此的配置可能會很麻煩。

        ActiveMQ 支援Mirrored Queues。Broker 會把傳送到某個 queue 的所有消

息轉發到一個名稱類似的topic,因此監控程式可以訂閱這個mirrored queue

topic。為了啟用Mirrored Queues,首先要將BrokerService 的useMirroredQueues

屬性設定成 true,然後可以通過destinationInterceptors 設定其它屬性,如

mirror topic 的字首,預設是"VirtualTopic.Mirror."。以下是ActiveMQ 配置文

件的一個例子:

<broker xmlns="http://activemq.apache.org/schema/core"

       brokerName="localhost" dataDirectory="${activemq.data}"

       useMirroredQueues="true">

       <amq:destinationInterceptors>

            <amq:mirroredQueue copyMessage="true" postfix="Mirror.Topic">

            </amq:mirroredQueue>

       </amq:destinationInterceptors>

 

12.3.     ActiveMQ的接收Wildcards模式

Wildcards 用來支援聯合的名字分層體系(federated name hierarchies)。它不是JMS 規範的一部分,而是ActiveMQ 的擴充套件。ActiveMQ 支援以下三種wildcards:

    "." 用於作為路徑上名字間的分隔符。

    "*" 用於匹配路徑上的任何名字。

    ">" 用於遞迴地匹配任何以這個名字開始的 destination。

12.4.     ActiveMQ虛擬主題

 

13.         ActiveMQ 消費者特性

13.1.     獨有消費者或者獨有佇列

Queue 中的訊息是按照順序被分發到 consumers 的。然而,當你有多個consumers同時從相同的 queue中提取訊息時,你將失去這個保證。因為這些訊息是被多個執行緒併發的處理。有的時候,保證訊息按照順序處理是很重要的。Broker會從多個 consumers中挑選一個 consumer來處理 queue中所有的訊息,從而保證了訊息的有序處理。如果這個 consumer失效,那麼 broker會自動切換到其它的 consumer。 可以通過 Destination Options 來建立一個 Exclusive Consumer:

queue  =  new  ActiveMQQueue("TEST.QUEUE?consumer.exclusive=true");     

consumer  =  session.createConsumer(queue);

如果存在 Exclusive Consumer 和普通的Consumer,那麼 Broker會首先把訊息傳送給Exclusive Consumer。除非該獨有消費者死亡。

13.2.     Message Group

Message Groups 可以看成是一種併發的 Exclusive Consumer。跟所有的訊息都由唯一的 consumer 處理不同,JMS 訊息屬性JMSXGroupID 被用來區分 message group。Message Groups 特性保證所有具有相同JMSXGroupID 的訊息會被分發到相同的 consumer(只要這個consumer 保持active)。

在一個訊息被分發到 consumer之前,broker首先檢查訊息JMSXGroupID屬性。如果存在,那麼 broker 會檢查是否有某個 consumer擁有這個 message group。如果沒有,那麼 broker會選擇一個consumer,並將它關聯到這個 message group。此後,這個 consumer 會接收這個message group 的所有訊息,直到:

 Consumer 被關閉;

 Message group 被關閉。通過傳送一個訊息,並設定這個訊息的JMSXGroupSeq 為-1。

開啟Message Group:

TextMessage message = session.createTextMessage("ActiveMq 傳送的訊息");

message.setStringProperty("JMSXFroupID", "TEST_GROUP_A");

關閉Message Group:

TextMessage message = session.createTextMessage("ActiveMq 傳送的訊息");

message.setStringProperty("JMSXFroupID", "TEST_GROUP_A");

message.setIntProperty("JMSXGroupSeq", -1);

 

13.3.     Message Slelectors

JMS Selectors 用於在訂閱中,基於訊息屬性和 Xpath 語法對進行訊息的過濾。

consumer  =  session.createConsumer(destination,  "JMSType  =  'car'  AND  weight  >  2500");

在JMS Selectors 表示式中,可以使用 IN、NOT IN、LIKE 等,例如:

       LIKE '12%3' ('123' true,'12993' true,'1234' false)

       LIKE 'l_se' ('lose' true,'loose' false)

       LIKE '\_%' ESCAPE '\' ('_foo' true,'foo' false)

       需要注意的是,JMS Selectors表示式中的日期和時間需要使用標準的long型毫秒值。另外表示式中的屬性不會自動進行型別轉換,例如:

myMessage.setStringProperty("NumberOfOrders",  "2");    

"NumberOfOrders > 1" 求值結果是false。

13.4.     訊息的重新傳遞和死信佇列

ActiveMQ需要重新傳遞訊息需要 Client 有以下幾種操作:

1.  Client 用了transactions 和呼叫了rollback()在session 中。

2.  Client 用了transactiions 和在呼叫commit()之前關閉。

3.  Client 在 CLIENT_ACKNOWLEDGE 的傳遞模式下在 session 中呼叫了

recover()。

只有最後一個事物提交後,訊息才能傳送到 broker 上,事物沒有提交前,整

個傳遞訊息仍處於事物中。一旦回滾,恢復以前情況。在 broker 端不知道訊息是

否處於重新傳遞狀態,這將會造成訊息分發開銷。

預設,aciaveMQ 中死佇列被宣告為“ActivemMQ.DLQ”,所有不能消費的消

息被傳遞到該死佇列中。你可以在 acivemq.xml中配置individualDeadLetterStrategy屬性

   <destinationPolicy>

     <policyMap>

       <policyEntries>

         <policyEntry queue= "> " >

           <deadLetterStrategy>

             <individualDeadLetterStrategy

               queuePrefix= "DLQ."  useQueueForQueueMessages= "true" />

           </deadLetterStrategy>

         </policyEntry>

       </policyEntries>

     </policyMap>

</destinationPolicy>

 

有時需要直接刪除過期的訊息而不需要傳送到死佇列中,xml 可以使用屬性

processExpired=false 來設定

<destinationPolicy>

    <policyMap>

      <policyEntries>

        <policyEntry queue= "> " >

          <deadLetterStrategy>

            <sharedDeadLetterStrategy processExpired= "false" />

          </deadLetterStrategy>

        </policyEntry>

      </policyEntries>

    </policyMap>

   </destinationPolicy>

 

存放非持久訊息到死佇列中

預設情況下,Activemq 不會把非持久的死訊息傳送到死佇列中。

 非永續性如果你想把非持久的訊息傳送到死佇列中,需要設定屬性

processNonPersistent=“true”

<destinationPolicy>

    <policyMap>

      <policyEntries>

        <policyEntry queue= "> " >

          <deadLetterStrategy>

            <sharedDeadLetterStrategy processNonPersistent= "true" />

          </deadLetterStrategy>

        </policyEntry>

      </policyEntries>

    </policyMap>

   </destinationPolicy>

 

13.5.     訊息優先順序值

JMS JMSPriority  定義了十個訊息優先順序值, 0  是最低的優先順序, 9  是最高的優先順序。另外,客戶端應當將0‐4  看作普通優先順序,5‐9  看作加急優先順序.

配置如下:

queue = new ActiveMQQueue("TEST.QUEUE?consumer.priority=10");

consumer = session.createConsumer(queue);

 

13.6.     慢訊息處理機制

目前ActiveMQ 使用 Pending Message Limit Strategy來解決慢訊息帶來的效能問題。除了prefetch buffer之外,你還要配置快取訊息的上限,超過這個上限後,新訊息到來時會丟棄舊訊息。通過在配置檔案的 destination map 中配置PendingMessageLimitStrategy,可以為不用的 topic namespace 配置不同的策略。

A:Pending Message Limit Strategy(等待訊息限制策略)目前有以下兩種:

  1. ConstantPendingMessageLimitStrategy

Limit 可以設定 0、>0、-1三種方式:

0表示:不額外的增加其預存大小。

>0表示:在額外的增加其預存大小。

-1表示:不增加預存也不丟棄舊的訊息。

這個策略使用常量限制:

<constantPendingMessageLimitStrategy limit="50"/>

  1. PrefetchRatePendingMessageLimitStrategy

這種策略是利用Consumer 的之前的預存的大小乘以其倍數等於現在的預存大小。

<prefetchRatePendingMessageLimitStrategy multiplier="2.5"/>

在以上兩種方式中,如果設定 0 意味著除了 prefetch 之外不再快取訊息;如果設定-1

意味著禁止丟棄訊息。

此外,你還可以配置訊息的丟棄策略,目前有以下兩種: 

oldestMessageEvictionStrategy。這個策略丟棄最舊的訊息。 

 oldestMessageWithLowestPriorityEvictionStrategy。這個策略丟棄最舊的,

而且具有最低優先順序的訊息。 

以下是個ActiveMQ配置檔案的例子:

<destinationPolicy> 

 <policyMap> 

 <policyEntries> 

 <policyEntry topic="PRICES.>"> 

<subscriptionRecoveryPolicy> 

<timedSubscriptionRecoveryPolicy recoverDuration="10000" /> 

</subscriptionRecoveryPolicy> 

<pendingMessageLimitStrategy> 

<constantPendingMessageLimitStrategy limit="10"/> 

</pendingMessageLimitStrategy> 

 </policyEntry> 

</policyEntries> 

</policyMap> 

</destinationPolicy>

 

13.7.     消費者追溯訊息

ActiveMQ支援6種恢復策略,可以自行選擇使用不同的策略

(一)   <fixedCountSubscriptionRecoveryPolicy>

這種策略限制在基於一個靜態的計數中對於主題(Topic)訊息快取的數量。

(二)   <fixedSizedSubscriptionRecoveryPolicy>

這種策略限制在記憶體使用量中對於主題(Topic)訊息快取的數量。這是

ActiveMQ 的預設持久恢復策略。你可以選擇設定 cache的大小來應用與所

有的主題[Topic]。

(三)   <lastImageSubscriptionRecoveryPolicy>

這種策略僅僅保持傳送到主題(Topic)的最後一個訊息。

(四)   <noSubscriptionRecoveryPolicy>

這種策略是不儲存主題訊息,不需要任何配置

(五)   <queryBasedSubscriptionRecoveryPolicy>

這種策略基於一個 JMS屬性選擇器應用到所有的訊息來設定其訊息快取的

大小

(六)   <timedSubscriptionRecoveryPolicy>

這種策略是基於應用到每個訊息的過期時間來限制其訊息快取數量。提示

這種訊息的生命週期時間來源於訊息傳送者設定其 timeToLive 引數