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>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值