ActiveMQ Consumer

獨有消費者(Exclusive Consumer)
Queue中的消息是按照順序被分發到consumers的。然而,當你有多個consumers同時從相同的queue中提取消息時,你將失去這個保證。因爲這些消息是被多個線程併發的處理。有的時候,保證消息按照順序處理是很重要的。例如,你可能不希望在插入訂單操作結束之前執行更新這個訂單的操作。
ActiveMQ從4.x版本起開始支持Exclusive Consumer。 Broker會從多個consumers中挑選一個consumer來處理queue中所有的消息,從而保證了消息的有序處理。如果這個consumer失效,那麼broker會自動切換到其它的consumer。 可以通過Destination Options 來創建一個Exclusive Consumer,如下:
queue = new ActiveMQQueue("TEST.QUEUE?consumer.exclusive=true");
consumer = session.createConsumer(queue);
還可以給consumer設置優先級,以便針對網絡情況進行優化,如下:

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

Consumer Dispatche Async(消息異步發送)
在activemq4.0以後,你可以選擇broker同步或異步的把消息分發給消費者。可以設置dispatchAsync 屬性,默認是true(異步),通常情況下這是最佳的。
你也可以修改,可以通過如下幾種方式
1:在ConnectionFactory層設置
((ActiveMQConnectionFactory)connectionFactory).setDispatchAsync(false);
2:在Connection上設置
這個設置將會覆蓋ConnectionFactory上的設置
((ActiveMQConnection)connection).setDispatchAsync(false);
3:在Consumer來設置
queue = new ActiveMQQueue("TEST.QUEUE?consumer.dispatchAsync=false");

consumer = session.createConsumer(queue);

Consumer Priority(優先級)
JMS JMSPriority 定義了十個消息優先級值,0 是最低的優先級,9 是最高的優先級。另外,客戶端應當將0‐4 看作普通優先級,5‐9 看作加急優先級。
如何定義Consumer Priority的優先級呢? 配置如下:
queue = new ActiveMQQueue("TEST.QUEUE?consumer.priority=10");
consumer = session.createConsumer(queue);

Consumer的Priority的劃分爲0~127個級別,127是最高的級別,0是最低的也是ActiveMQ默認的。 這種配置可以讓Broker根據Consumer的優先級來發送消息先到較高的優先級的Consumer上,如果某個較高的Consumer的消息裝載慢,則Broker會把消息發送到僅次於它優先級的Consumer上。

Manage Durable Subscribers(持久化管理)
消息的持久化,保證了消費者離線後,再次進入系統,不會錯過消息,但是這也會消耗很多的資源。從5.6開始,可以對持久化消息進行如下管理:
Removing inactive subscribers(刪除持久化訂閱)
我們還可能希望刪除那些不活動的訂閱者,如下:
<broker name="localhost" offlineDurableSubscriberTimeout="86400000"
offlineDurableSubscriberTaskSchedule="3600000">
1: offlineDurableSubscriberTimeout:離線多長時間就過期刪除,缺省是-1,就是不刪除

2: offlineDurableSubscriberTaskSchedule:多長時間檢查一次,缺省300000,單位毫秒

Message Groups(消息分組)
Message Groups就是對消息分組,它是Exclusive Consumer功能的增強:
邏輯上,Message Groups 可以看成是一種併發的Exclusive Consumer。跟所有的消息都由唯一的consumer處理不同,JMS 消息屬性JMSXGroupID 被用來區分message group。
Message Groups特性保證所有具有相同JMSXGroupID 的消息會被分發到相同的consumer(只要這個consumer保持active)。
另外一方面,Message Groups特性也是一種負載均衡的機制。 在一個消息被分發到consumer之前,broker首先檢查消息JMSXGroupID屬性。如果存在,那麼broker 會檢查是否有某個consumer擁有這個message group。如果沒有,那麼broker會選擇一個consumer,並將它關聯到這個message group。此後,這個consumer會接收這個message group的所有消息,直到:
1:Consumer被關閉
2:Message group被關閉,通過發送一個消息,並設置這個消息的JMSXGroupSeq爲-1
創建一個Message Groups,只需要在message對象上設置屬性即可,如下:

message.setStringProperty("JMSXGroupID","GroupA");

關閉一個Message Groups,只需要在message對象上設置屬性即可,如下:
message.setStringProperty("JMSXGroupID","GroupA");

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

Message Selectors(消息選擇器)
JMS Selectors用在獲取消息的時候,可以基於消息屬性和Xpath語法對消息進行過濾。JMS Selectors由SQL92語義定義。以下是個Selectors的例子:
consumer = session.createConsumer(destination, "JMSType = 'car' AND weight > 2500");
1:JMS Selectors表達式中,可以使用IN、NOT IN、LIKE等
2:需要注意的是,JMS Selectors表達式中的日期和時間需要使用標準的long型毫秒值
3:表達式中的屬性不會自動進行類型轉換,例如:
myMessage.setStringProperty("NumberOfOrders", "2");
那麼此時“NumberOfOrders > 1” 求值結果會是false
4:Message Groups雖然可以保證具有相同message group的消息被唯一的consumer順序處理,但是卻不能確定被哪個consumer處理。在某些情況下,Message Groups可以和JMS Selector一起工作,
例如:設想有三個consumers分別是A、B和C。你可以在producer中爲消息設置三個message
groups分別是“A”、“B”和“C”。然後令consumer A使用“JMXGroupID = ‘A’”作爲selector。B
和C也同理。這樣就可以保證message group A的消息只被consumer A處理。需要注意的是,這種做法有
以下缺點:
(1)producer必須知道當前正在運行的consumers,也就是說producer和consumer被耦合到一起。

(2)如果某個consumer失效,那麼應該被這個consumer消費的消息將會一直被積壓在broker上。

Redelivery Policy(重新發送策略)
ActiveMQ在接收消息的Client有以下幾種操作的時候,需要重新傳遞消息:
1:Client用了transactions,且在session中調用了rollback()
2:Client用了transactions,且在調用commit()之前關閉
3:Client在CLIENT_ACKNOWLEDGE的傳遞模式下,在session中調用了recover()
可以通過設置ActiveMQConnectionFactory和ActiveMQConnection來定製想要的再次傳送策略,可用的Redelivery屬性如下:
1:collisionAvoidanceFactor:設置防止衝突範圍的正負百分比,只有啓用useCollisionAvoidance參數時才生效。也就是在延遲時間上再加一個時間波動範圍。默認值爲0.15
2:maximumRedeliveries:最大重傳次數,達到最大重連次數後拋出異常。爲-1時不限制次數,爲0時表示不進行重傳。默認值爲6(當超過重傳次數,將進入DLQ中)。
3:maximumRedeliveryDelay:最大傳送延遲,只在useExponentialBackOff爲true時有效(V5.5),假設首次重連間隔爲10ms,倍數爲2,那麼第二次重連時間間隔爲 20ms,第三次重連時間間隔爲40ms,當重連時間間隔大的最大重連時間間隔時,以後每次重連時間間隔都爲最大重連時間間隔。默認爲-1。
4:initialRedeliveryDelay:初始重發延遲時間,默認1000L
5:redeliveryDelay:重發延遲時間,當initialRedeliveryDelay=0時生效,默認1000L
6:useCollisionAvoidance:啓用防止衝突功能,默認false
7:useExponentialBackOff:啓用指數倍數遞增的方式增加延遲時間,默認false

8:backOffMultiplier:重連時間間隔遞增倍數,只有值大於1和啓用useExponentialBackOff參數時才生

在接受的Client可以如下設置:
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(
"failover:(tcp://192.168.1.106:61679,tcp://192.168.1.106:61819)?randomize=false");
RedeliveryPolicy policy = new RedeliveryPolicy();
policy.setMaximumRedeliveries(3);
cf.setRedeliveryPolicy(policy);
當消息試圖被傳遞的次數超過配置中maximumRedeliveries屬性的值時,那麼,broker會認定該消息是一個死消息,並被把該消息發送到死隊列中。 默認,aciaveMQ中死隊列被聲明爲“ActivemMQ.DLQ”,所有不能消費的消息都被傳遞到該死隊列中。 你可以在acivemq.xml中配置individualDeadLetterStrategy屬性,示例如下:
<policyEntry queue= "> " >
<deadLetterStrategy>
<individualDeadLetterStrategy queuePrefix= "DLQ."
useQueueForQueueMessages= "true" />
</deadLetterStrategy>

</policyEntry>

自動刪除過期消息
有時需要直接刪除過期的消息而不需要發送到死隊列中,可以使用屬性
processExpired=false來設置,示例如下:
<policyEntry queue= "> " >
<deadLetterStrategy>
<sharedDeadLetterStrategy processExpired= "false" />
</deadLetterStrategy>
</policyEntry>
存放非持久消息到死隊列中
默認情況下,Activemq不會把非持久的死消息發送到死隊列中。非持久性如果你想把非持久的消息發送到死隊列中,需要設置屬性processNonPersistent=“true”,示例如下:
<policyEntry queue= "> " >
<deadLetterStrategy>
<sharedDeadLetterStrategy processNonPersistent= "true" />
</deadLetterStrategy>

</policyEntry>

Redelivery Policy per Destination
在V5.7之後,你可以爲每一個Destination配置一個Redelivery Policy。示例如:
ActiveMQConnection connection ... // Create a connection
RedeliveryPolicy queuePolicy = new RedeliveryPolicy();
queuePolicy.setInitialRedeliveryDelay(0);
queuePolicy.setRedeliveryDelay(1000);
queuePolicy.setUseExponentialBackOff(false);
queuePolicy.setMaximumRedeliveries(2);
RedeliveryPolicy topicPolicy = new RedeliveryPolicy();
topicPolicy.setInitialRedeliveryDelay(0);
topicPolicy.setRedeliveryDelay(1000);
topicPolicy.setUseExponentialBackOff(false);
topicPolicy.setMaximumRedeliveries(3);
// Receive a message with the JMS API
RedeliveryPolicyMap map = connection.getRedeliveryPolicyMap();
map.put(new ActiveMQTopic(">"), topicPolicy);

map.put(new ActiveMQQueue(">"), queuePolicy);

Consumer Handling
Prefetch機制
ActiveMQ通過Prefetch機制來提高性能,方式是在客戶端的內存裏可能會緩存一定數量的消息。緩存消息的數量由prefetch limit來控制。當某個consumer的prefetch buffer已經達到上限,那麼broker不會再向consumer分發消息,直到consumer向broker發送消息的確認,確認後的消息將會從緩存中去掉。
可以通過在ActiveMQConnectionFactory或者ActiveMQConnection上設置ActiveMQPrefetchPolicy對象來配置prefetch policy。也可以通過connection options或者destination options來配置。例如:
tcp://localhost:61616?jms.prefetchPolicy.all=50
tcp://localhost:61616?jms.prefetchPolicy.queuePrefetch=1
queue = new ActiveMQQueue("TEST.QUEUE?consumer.prefetchSize=10");
prefetch size的缺省值如下:
1:persistent queues (default value: 1000)
2:non-persistent queues (default value: 1000)
3:persistent topics (default value: 100)

4:non-persistent topics (default value: Short.MAX_VALUE -1)

慢Consumer處理
慢消費者會在非持久的topics上導致問題:一旦消息積壓起來,會導致broker把大量消息保存在內存中,broker也會因此而變慢。目前ActiveMQ使用Pending Message Limit Strategy來解決這個問題。除了prefetch buffer之外,你還要配置緩存消息的上限,超過這個上限後,新消息到來時會丟棄舊消息。
通過在配置文件的destination map中配置PendingMessageLimitStrategy,可以爲不用的topic namespace配置不同的策略。
Pending Message Limit Strategy(等待消息限制策略)目前有以下兩種:
1: Constant Pending Message Limit Strategy
Limit可以設置0、>0、-1三種方式: 0表示:不額外的增加其預存大小。 >0表示:再額外的增加其預存大小。 -1表示:不增加預存也不丟棄舊的消息。 這個策略使用常量限制,配置如下:
<constantPendingMessageLimitStrategy limit="50"/>
2:Prefetch Rate Pending Message Limit Strategy
這種策略是利用Consumer的之前的預存的大小乘以其倍數等於現在的預存大小。比如:
<prefetchRatePendingMessageLimitStrategy multiplier="2.5"/>

3:說明:在以上兩種方式中,如果設置0意味着除了prefetch之外不再緩存消息;如果設置-1意味着禁止丟棄消息。

配置消息的丟棄策略,目前有三種方式:
1:oldestMessageEvictionStrategy:這個策略丟棄最舊的消息。
2:oldestMessageWithLowestPriorityEvictionStrategy:這個策略丟棄最舊的,而且具有最低優先級的消息。
3:uniquePropertyMessageEvictionStrategy:從5.6開始,可以根據自定義的屬性來進行拋棄,比如<uniquePropertyMessageEvictionStrategy propertyName=“STOCK” />,這就表示拋棄屬性名稱爲Stock的消息
配置示例:
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry topic="FOO.>">
<dispatchPolicy>
<roundRobinDispatchPolicy />
</dispatchPolicy>

</policyEntry>

<policyEntry topic="ORDERS.>">
<dispatchPolicy>
<strictOrderDispatchPolicy />
</dispatchPolicy>
</policyEntry>
<policyEntry topic="PRICES.>">
<!-- lets force old messages to be discarded for slow consumers -->
<pendingMessageLimitStrategy>
<constantPendingMessageLimitStrategy limit="10"/>
</pendingMessageLimitStrategy>
</policyEntry>
<policyEntry tempTopic="true" advisoryForConsumed="true" />
<policyEntry tempQueue="true" advisoryForConsumed="true" />
</policyEntries>
</policyMap>
</destinationPolicy>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章