ActiveMq 消费者 特性

消费者特性:
1、Consumer Dispatch Async
    默认情况下ActiveMQ服务端采用异步方式向客户端推送消息,
    从ActudiMQv4开始,已经可以配置broker向消费者转发消息的机制是同步或者是异步,
    你可以选择在connection URI, Connection,ConnectionFactory,consumer不同级别上设置
         你可以选择对低速消费者设置为异步消息传递,对快速消费者设置为同步消息消费(减少上下文切换成本)。
     采用同步消息的缺点是:如果向一个低速消费者发送消息,生产者将会被堵塞。
         默认值dispatchAsync=true,这是高性能的最佳设置,低速消费者想要更好性能则采用异步机制,
     如果消息消费过程中低速消费者出现概率很低,并且你想要更好的吞吐量,可以设置为同步机制。
     注意:不同级别上设置见官网http://activemq.apache.org/consumer-dispatch-async.html
2、Consumer Priority
    除了可插拔的调度策略,例如轮询。ActiveMQ还支持消费者优先级设置。
    Consumer的Priority的划分为0~127个级别,127是最高的级别,0是最低的也是ActiveMQ默认的
    broker 通过消费者的权重进行排序,优先将消息发送给最高优先级的消费者。
    一旦特定优先的消费者prefetch buffer满了,broker将把消息发送给次级且prefetch buffer未满的消费者。
3、Exclusive Consumer
    ActiveMQ在队列保持消息的顺序,并且按序转发给消费者。
    如果你有多个消费者监听一个队列就不会保证消息肯定是按序消费的
    因为消息是被不同的线程处理的。
    有时候,保证消息的顺序性是很重要的,例如:你不想在一个插入订单之前去跟新
    订单。
    ActiveMQ从4.x版本起开始支持Exclusive Consumer。 Broker会从多个consumers中挑选一个consumer来处理queue中所有的消息,从而保证了消息的有序处理。如果这个consumer失效,那么broker会自动切换到其它的consumer。 可以通过Destination Options 来创建一个Exclusive Consumer,如下:
    从而来保证消息顺序性。如果当前消费者fails,broker会自动故障转义选择另外一个消费者。从而实现高可用。
4、Manage Durable Subscribers(持久化订阅)
    对于长期离线的的订阅者是不希望出现的。因为broker将会长期保存所有未发送给该离线消费者的消息。
    最终可能将导致ActiveMQ系统整体减速。你可以使用JConsole 或者 Web Console类似这样的管理工具,
    手动注销不活动的订阅者,或者其他更多设置... 介于此我们在5.6版本做了如下一些改进。

    a、删除过期消息
           一些应用会指定消息的过期时间,如果到了过期时间,到了过期时间,broker为离线订阅者保存的消息将被删除。
        默认30秒检查一次过期消息,我们可以用destination policy策略调整,如:
        <policyEntry topic=">" expireMessagesPeriod="300000"/> 指定broker 5分钟检查过期消息

    b、删除过期订阅者
  <broker name="localhost" offlineDurableSubscriberTimeout="86400000" offlineDurableSubscriberTaskSchedule="3600000">
        1: offlineDurableSubscriberTimeout:离线多长时间就过期删除,缺省是-1,就是不删除

        2: offlineDurableSubscriberTaskSchedule:多长时间检查一次,缺省300000,单位毫秒
5、Message Groups
     Message Groups是Exclusive Consume的增强,有如下特点:
    a、保证在单个队列中处理相关消息(JMSXGroupID)的顺序
    b、多个消费者就是实现了负载均衡处理消息
    c、高可用/故障自动转移如果一个JVM fail
    所以Message Groups就像一个并行的Exclusive Consumer。 通过JMS header JMSXGroupID
    来定义一组消息。同一消息组的所有消息将会发送给同一个消费者。(只要这个consumer保持active)
    一旦消费者die会选择另一个消费者

   考虑到会有大量消息组,所有hash buckets会替代JMSXGroupID string使用。在一个消息被分发到consumer之前,broker首先检查消息JMSXGroupID属性,如果存在,那么broker 会检查是否有某个        consumer拥有这个message group,如果没有,那么broker会选择一个consumer,并将它关联到这个message group。此后,这个consumer会接收这个message group的所有消息。直到:

    a、Consumer被关闭
    b、Message group被关闭,通过发送一个消息,并设置这个消息的JMSXGroupSeq为-1

    在发送消息之前先进行分组,一组消息批量发送过去。如果内存中一组消息过大并且超出 maxPageSize( 控制进入内存中的消息数量) 会阻塞其他组消息的接收。可以适当调整maxPageSize默认值。

    JMSXGroupFirstForConsumer
  从4.1版本开始,ActiveMQ支持一个boolean类型的header属性JMSXGroupFirstForConsumer,当某个message group的第一个消息被发送到consumer的时候,这个字段被设置。如果客户使用failover transport连接到broker。在由于网络问题等造成客户重新连接到broker的时候,新的消费者实例将被创建(依然接收之前的消息group),因此JMSXGroupFirstForConsumer字段也会被重新设置。

Adding New Consumers

如果broker中存在即将发送的消息,并且即将添加一个新的消费者,那么消息延迟发送很有必要,如果你不这样做第一个消费者可能将会收到所有消息组所有消息。如果俩个属性值都被设置大于0,那么当所有消费者准备就绪或者达到timeBeforeDispatchStarts时间消息才会被发送.如果只设置consumersBeforeDispatchStarts则消费者链接的超时时间(timeBeforeDispatchStarts)1秒,如果所有的消费者都链接中断,当下一个消费者连接上后消息发送延迟策略将再被再次应用。

consumersBeforeDispatchStarts:让消费者达到一定数量再开始负载消费

timeBeforeDispatchStarts:让消费者延迟一段时间再开始负载消费

Competing demands of memory consumption, load balancing, complexity, etc...待续

6、Redelivery Policy( 重新发送策略)

消息重发的详细信息涉及消息重发和DLQ(不能被消费的消息存放队列)。你可以在ActiveMQConnectionFactory或者ActiveMQConnection设置RedeliveryPolicy策略。在V5.7之后,你可以为每一个Destination配置一个Redelivery Policy。

ActiveMQ在接收消息的Client有以下几种操作的时候,需要重新传递消息:
a:Client用了transactions,且在session中调用了rollback()
b:Client用了transactions,且在调用commit()之前关闭
c:Client在CLIENT_ACKNOWLEDGE的传递模式下,在session中调用了recover()

可以通过设置ActiveMQConnectionFactory和ActiveMQConnection来定制想要的再次传送策略,可用的Redelivery属性如下:
a:collisionAvoidanceFactor:设置防止冲突范围的正负百分比,只有启用useCollisionAvoidance参数时才生效。也就是在延迟时间上再加一个时间波动范围。默认值为0.15
b:maximumRedeliveries:最大重传次数,达到最大重连次数后抛出异常。为-1时不限制次数,为0时表示不进行重传。默认值为6(当超过重传次数,将进入DLQ中)。
c:maximumRedeliveryDelay:最大传送延迟,只在useExponentialBackOff为true时有效(V5.5),假设首次重连间隔为10ms,倍数为2,那么第二次重连时间间隔为 20ms,第三次重连时间间隔为40ms,当重连时间间隔大的最大重连时间间隔时,以后每次重连时间间隔都为最大重连时间间隔。默认为-1。
d:initialRedeliveryDelay:初始重发延迟时间,默认1000L
e:redeliveryDelay:重发延迟时间,当initialRedeliveryDelay=0时生效,默认1000L
f:useCollisionAvoidance:启用防止冲突功能,默认false
g:useExponentialBackOff:启用指数倍数递增的方式增加延迟时间,默认false
h: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);

7、Retroactive Consumer(可追溯消费者)

   只针对JMS TOPIC消费者,如果订阅者可追溯,他可以获取实例创建之前的消息。通常订阅者不可能获取实例创建之前的消息,因为broker根本不知道他的存在,对于broker而言,如果一个topic通道创建,且有发布者发布消息,那么broker将会在内存中或者磁盘中保存已经发布的消息。知道所有订阅者都消费才会清楚原始消息。如果是Retroactive consumer可以获取这些broker上还保存的旧消息。

8、Selectors(选择器)

  在Consumer中使用Selectors可以帮助broker过滤消息,Selectors使用SQL 92语法,通常适用于消息头。ActiveMQ还支持XPath选择器。JMS规范指出,在选择器使用字符串属性不能转化为数值类型。比如:你将一个age设置为字符串“21” 那么选择器不能这样使用 ‘age>18’。因为ActiveMQ支持STOMP(只发送字符串类型的属性)客户端。如果你想要JMS selectors 自动将字符串类型转为适当的数值类型,只需要加入前缀符(convert_string_expressions)修饰selector 例如‘convert_string_expressions:age > 18’

当Consumer创建之后,将会把selector信息传递给broker,此后再consumer的整个生命周期中,都将有效,不过一旦指定selector,重复设定selector将不会有效,除非关闭consumer并重建实例。

==============================摘抄===================================================

在Topic和Queue使用selector的时机,有所不同

对于Queue而言,broker在dispatch每条消息时,都会遍历整个消费者列表,并匹配selector表达式,一旦匹配成功则将消息发送给Consumer,如果所有的selector都无法匹配,消息将沉积。注意,这些沉积的消息将会在每次pageIn时都会被加载而且也会在内存中不断叠加(直到过期),将会对Queue的转发效率带来很大的危险,如果你发现Queue的消息大量积压(undeque),你应该检测是否与selector有关。如果你使用了selector,你一定要让全局中所有的selector覆盖所有的消息,或者至少有一个没有selector的consumer。(参看源码:Queue,QueueDispatchSelector)

对于Topic而言,似乎有些不同,主要是在selector应用的时机上;如果订阅者是durable(耐久的),那么订阅者的ClientId + selector信息都会被持久化保存(参见TopicMessageStore),此后即使订阅者离线,符合selector的消息,仍然会为它创建消息副本(为当前订阅者ID 与messageId的列表关系,但实际消息只有一条),如果selector不匹配,存储器将不会为此订阅者创建消息副本,也意味着当此订阅者上线后将不会感知到任何事情,就像那些消息从来都没有出现过一样;不过在broker转发消息给订阅者之前,仍然会使用selector匹配;因为订阅者可以修改selector,为了避免现有的消息副本不适合新的selector,将会在消息发送给订阅者时也使用selector匹配,对于不匹配selector的消息,此时将会按照“已消费”来处理,它们也不会发送给订阅者。此处需要提醒,创建durable类型的订阅者时,需要在connection上指定ClientId,全局中同一个Topic上所有的ClientId都不能相同,且同一个Connection上,不能创建多个duarable订阅者。

如果订阅者是非durable(即为temporary),也就不存在创建消息副本的情况,那么将会在消息转发给订阅者之前检测即可。

    (源码参见:Topic,DurableTopicSubscription,TopicMessageStore,RoundRobinDispatchPolicy等)

==============================摘抄===================================================

9、Slow Consumer Handling

      slow consumer 在非持久化订阅中,迫使broker在内存保存旧的消息,一旦内存已满,broker会迫使生产者降低生产速度,

      从而快速消费者也会降低消费速度。我们可以在ActiveMQ后续版本中选择将积压消息保存到临时文件,但这种方式也会降低

      快速消费者速度。

      目前我们采取的策略是除了消费者prefetch buffer 可以配置broker对消费者保留的最大消息数。一旦打到最大消息数,当新消息进来,旧消息就被会删除,这种策略能保证内存保存最新消息,broker会一直不断向slow consumer发送消息,但是以丢弃旧消息为前提。

a)PendingMessageLimitStrategy (等待消息限制策略 此策略只对Topic有效,只对nondurable订阅者有效):

该策略是要在RAM为消费者保存待处理消息最大数目(高于prefetch size),目前有俩种策略

a1): Constant Pending Message Limit Strategy

  Limit可以设置0、>0、-1三种方式: 

    0表示:不额外的增加其预存大小。 

    >0表示:再额外的增加其预存大小。 

    -1表示:不增加预存也不丢弃旧的消息。 

  这个策略使用常量限制,配置如下:

    <constantPendingMessageLimitStrategy limit="50"/>

a2):Prefetch Rate Pending Message Limit Strategy

  这种策略是利用Consumer的之前的预存的大小乘以其倍数等于现在的预存大小。比如:<prefetchRatePendingMessageLimitStrategy multiplier="2.5"/>

 

b)Using the Prefetch Policy to Configure the Limit

JMS客户端有一个prefetch policy(预存储)策略,可以用来配置持久化和非持久化Queue和Topics各种prefetch limits。prefetch policy 还可以允许你在connection/consumer上指定maximumPendingMessageLimit属性值。

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)

c)Configuring the Eviction Policy(消息丢弃策略)

MessageEvictionStrategy 在slow consumer中用来决定哪一个消息应该被丢弃。默认实现类是oldestMessageEvictionStrategy。

你可以自定义实现类。定义自己的丢弃规则。目前有三种丢弃策略

   1) OldestMessageEvictionStrategy: 移除旧消息,默认策略。

    2) OldestMessageWithLowestPriorityEvictionStrategy: 旧数据中权重较低的消息,将会被移除。(message.getPriority())

    3) UniquePropertyMessageEvictionStrategy: 移除具有指定property的旧消息。开发者可以指定property的名称,从此属性值相同的消息列表中移除较旧的(根据消息的创建时间)

tips:

建议将你的慢消费者的prefetch size设置的比快消费者的prefetch size低一些。

Monitoring :

你可以使用JMX控制台查看活跃的订阅者统计信息。

discarded:成为慢消费者后丢弃的消息数。
matched:预存缓冲区待发消息的个数,有些值预示着prefetch buffer已满
 

10、Subscription Recovery Policy

订阅恢复策略可以及时重获你丢失的主题消息,比如你链接的broker A down掉了 你重连到集群中broker B,你可能丢失消息。

所以ActiveMQ支持一个定时或者固定大小的恢复换重复,以便在某段时间内你重连到broker B 你丢失的消息的消息能被重新发送。

在非持久订阅者“失效”期间或一个新的Topic,broker可以保留的可追溯的消息量。前提是Topic必须是“retroactive”,我们可以在distination地址中指定此属性,例如:"order.topic?consumer.retroactive=true"。默认情况下,订阅者只能获取“订阅”开始之后的消息,如果Retroactive=true,那么订阅者就可以获取其创建之前的消息列表。此Policy就是用来控制“retroactive”的消息量。

a) FixedSizedSubscriptionRecoveryPolicy: 保存一定size的消息,broker将为此Topic开辟定额的RAM用来保存最新的消息。

b) FixedCountSubscriptionRecoveryPolicy: 保存一定条数的消息。

c) LastImageSubscriptionRecoveryPolicy: 只保留最新的一条数据

d) QueryBasedSubscriptionRecoveryPolicy: 符合置顶selector的消息都将被保存,具体能够“恢复”多少消息,由底层存储机制决定;比如对于非持久化消息,只要内存中还存在,则都可以恢复。

e) TimedSubscriptionRecoveryPolicy: 保留最近一段时间的消息。

 f) NoSubscriptionRecoveryPolicy: 关闭“恢复机制”。默认值。

 

 

 


        

  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值