ActiveMQ - 策略与配置

本文详细介绍了ActiveMQ的各种策略配置,包括消息重发、死信队列、消息转发、消息预获取、消息回溯、消息限制、消息剔除、慢速消费者策略、消息转存策略等,帮助理解ActiveMQ在不同场景下的行为和优化措施。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. 消息重发 

先给出Spring整合ActiveMQ的相关重发配置。 

<bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
    <property name="maximumRedeliveries" value="6"/>
    <property name="initialRedeliveryDelay" value="0"/>
    <property name="redeliveryDelay" value="1000"/>
    <property name="useExponentialBackOff" value="false"/>
    <property name="backOffMultiplier" value="5"/>
    <property name="maximumRedeliveryDelay" value="30000"/>
    <property name="useCollisionAvoidance" value="true"/>
    <property name="collisionAvoidancePercent" value="15"/>
</bean>

maximumRedeliveries:最大重发次数。默认值:6。

initialRedeliveryDelay:初始重发延迟。默认值:1000L

redeliveryDelay:重发延迟。当initialRedeliveryDelay为0时,生效。默认值:-1L

useExponentialBackOff:使用指数增加延迟。默认值:false

backOffMultiplier:延迟的指数。默认值:5

maximumRedeliveryDelay:最大重发延迟。默认值:-1

useCollisionAvoidance:使用冲突避免,默认值:false

collisionAvoidancePercent:冲突范围的百分比,默认值:15

 


重发机制的触发:

1. 使用事务的session,调用rollback

2. 使用事务的session,在commit之前调用close

3. 使用session.client_acknowledge,并且调用session.recover

4. 客户端连接超时

在Spring整合的ActiveMQ的框架中。需要在

DefaultMessageListenerContainer 这个bean中,
<property name="sessionTransacted" value="true"/>
<property name="sessionAcknowledgeMode" value="0"/>

或者:

<property name="sessionTransacted" value="false"/>
<property name="sessionAcknowledgeMode" value="2"/>

 防止消息重复消费

  •  生产者生产消息时,附带分布式全局唯一id,比如Twitter的SnowFlake算法。
  • 消费者消费之前,检验Redis中是否含有指定的id。
  • 如果不存在,把这个id放进Redis(可以设定生存时间,根据重发机制延迟时间计算)。如果存在,不消费。
  • 消费者进行消费。消费成功后,(暂时不删除这个id,不同于订单操作)
  • (有可能消费者消费失败,但是Redis不会进行回滚,需要删除这个键)

二. 死信队列

进入死信队列的条件:

  • 消息过期
  • 重发次数达到最大, 依然不能被正常消费

DeadLetterStrategy

有两个重要参数:processExpired和processNonPersistent分别是是否将过期消息或者非持久化的消息放到私信队列里。默认值true和false。 

  •  IndividualDeadLetterStrategy:把DeadLetter放入各自的死信通道中。对于topic,前缀为:ActiveMQ.DLQ.Topic。对于queue,前缀是ActiveMQ.DLQ.Queue。无论是topic还是queue,broker默认使用Queue保存DeadLetter,也可以指定为Topic。

<policyEntry queue="order">  
  <deadLetterStrategy>  
    <individualDeadLetterStrategy  
      queuePrefix="DLQ." useQueueForQueueMessages="true" />  
  </deadLetterStrategy>  
</policyEntry>

 

queuePrefix:设置队列的前缀名。

topicPrefix:设置话题的前椎名。

useQueueForQueueMessages:使用queue保存死信队列。如果为false,则使用topic保存死信队列。


 

  •  SharedDeadLetterStrategy:默认策略。将所有的死信队列保存在一个共享的队列中。默认为:ActiveMQ.DLQ。也可以指定。

 


<deadLetterStrategy>  
    <sharedDeadLetterStrategy deadLetterQueue="DLQ-QUEUE"/>  
 </deadLetterStrategy> 

 


  • DiscardingDeadLetterStrategy:抛弃所有的死信队列。 
<broker>  
    <plugins>  
      <discardingDLQBrokerPlugin dropAll="true" dropTemporaryTopics="true" dropTemporaryQueues="true" />  
    </plugins>  
</broker> 

 


 三. 消息转发

 broker转发消息给多个consumer时,发送的顺序性。

DispatchPolicy

Topic: 

  • roundRobinDispatchPolicy:“轮询”,将消息依次发送给每个“订阅者”,按照订阅列表的先后顺序,发送给第一个订阅者后,第一个订阅者被移动到订阅列表尾部,以此类推。
  • strictOrderDispatchPolicy:严格有序,使用synchronized,同一时间内只能转发给一个消费者。消费者没有移动顺序的改变。
  • priorityDispatchPolicy:基于priority排序。默认每个消费者的priority都是一样的,继承于simpleDispatchPolicy。
  • simpleDispatchPolicy:按照当前订阅列表排序。
  • priorityNetworkDispatchPolicy :忽略较低优先级的网络消费者,与网桥一起使用,支持重复的topic订阅。继承于simpleDispatchPolicy
<policyEntry topic=">">                 
  <dispatchPolicy>    
   <roundRobinDispatchPolicy/>  
  </dispatchPolicy>  
</policyEntry>

 

Queue:

  • strictOrderDispatch:若为true,当消费者的prefetchSize满了,就向下一个消费者发送消息。 如果为false,则不等消费者预获取区满了,就向下一个消费者发送消息。
<policyEntry queue =">" strictOrderDispatch ="true"/> 

四. 消息预获取 

  • persistent queues (default value: 1000)

  • non-persistent queues (default value: 1000)

  • persistent topics (default value: 100)

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

 设置相对较高的预取值可以提高性能。因此,对于主题,默认值通常大于1000且更高,对于非持久性消息,默认值仍然更高。预取大小决定了客户端RAM中保存的消息数量,因此如果RAM有限,您可能需要设置较低的值,如1或10等。如果每个消息消费的时间较长,可以适当降低值。

    <bean id="prefetchPolicy" class="org.apache.activemq.ActiveMQPrefetchPolicy">
        <property name="queuePrefetch" value="1000"/>
        <property name="queueBrowserPrefetch" value="500"/>
        <property name="topicPrefetch" value="32766"/>
        <property name="durableTopicPrefetch" value="100"/>
        <property name="optimizeDurableTopicPrefetch" value="1000"/>
        <property name="maximumPendingMessageLimit" value="32766"/>
    </bean>

 

(注:以上为默认值) 

在activemq的连接工厂中添加:<property name="prefetchPolicy" ref="prefetchPolicy"/>

五. 消息回溯

解决了什么问题?生产者在某topic中发送了多条消息后,这时候non-durable类型的消费者才订阅,获取不到之前生产者发送的信息。再者,由于网络问题,non-durable类型的消费者处于inactive状态,无法接收到生产者此刻发送的消息。使用SubscriptionRecoveryPolicy可以解决上述问题。前提它的retroactive属性设置为true。即consumer.retroactive=true
 

<property name="useRetroactiveConsumer" value="true"/>

 

SubscriptionRecoveryPolicy(订阅恢复策略) 

 

FixedSizedSubscriptionRecoveryPolicy:保留固定字节的记录

<policyEntry topic=">">
    <subscriptionRecoveryPolicy>
        <fixedSizedSubscriptionRecoveryPolicy maximumSize="1024"/>
    </subscriptionRecoveryPolicy>
</policyEntry> 

FixedCountSubscriptionRecoveryPolicy:保留固定数量的记录

<policyEntry topic=">">
    <subscriptionRecoveryPolicy>
        <fixedCountSubscriptionRecoveryPolicy maximumSize="100"/>
    </subscriptionRecoveryPolicy>
</policyEntry> 

LastImageSubscriptionRecoveryPolicy:保留最近一条记录

 <policyEntry topic=">">
    <subscriptionRecoveryPolicy>
        <lastImageSubscriptionRecoveryPolicy/>
    </subscriptionRecoveryPolicy>
</policyEntry>

NoSubscriptionRecoveryPolicy:禁用回溯。(默认配置)

 <policyEntry topic=">">
    <subscriptionRecoveryPolicy>
        <noSubscriptionRecoveryPolicy/>
    </subscriptionRecoveryPolicy>
</policyEntry>

QueryBasedSubscriptionRecoveryPolicy:根据查询机制来使用回溯

 <policyEntry topic=">">
    <subscriptionRecoveryPolicy>
        <queryBasedSubscriptionRecoveryPolicy query="Color='red' AND Name='tom'"/>
    </subscriptionRecoveryPolicy>
</policyEntry>
 

TimedSubscriptionRecoveryPolicy:保留指定时间内的记录

 <policyEntry topic=">">
    <subscriptionRecoveryPolicy>
        <timedSubscriptionRecoveryPolicy recoverDuration="60000"/>
    </subscriptionRecoveryPolicy>
</policyEntry>

RetainedMessageSubcriptionRecoveryPolicy:保留ActiveMQ.Retain属性值为true的最后一条消息

<policyEntry topic=">">
    <subscriptionRecoveryPolicy>
        <retainedMessageSubscriptionRecoveryPolicy/>
    </subscriptionRecoveryPolicy>
</policyEntry>

 


六. 消息限制(针对慢消费者)

此策略只对Topic有效,只对nondurable订阅者有效,当通道中有大量的消息积压时,broker可以保留的消息量。为了防止Topic中有慢速消费者,导致整个通道消息积压。(对于Topic而言,一条消息只有所有的订阅者都消费才会被删除) 

PendingMessageLimitStrategy 

  •  ConstantPendingMessageLimitStrategy:保留固定条数的消息,如果消息量超过limit,将使用“MessageEvictionStrategy”移除消息(参见下文)。
<policyEntry topic="PRICES.>">  
    <!-- lets force old messages to be discarded for slow consumers -->  
    <pendingMessageLimitStrategy>  
        <constantPendingMessageLimitStrategy limit="50"/>  
    </pendingMessageLimitStrategy>  
</policyEntry>  

 

  • PrefetchRatePendingMessageLimitStrategy: 保留prefetchSize倍数条消息。
<!-- 如果prefetchSize为100,则保留2.5 * 100条消息 -->  
<prefetchRatePendingMessageLimitStrategy multiplier="2.5"/>  

 

 


 七. 消息剔除(针对慢消费者)

 配合PendingMessageLimitStrategy,只对Topic有效,只对nondurable订阅者有效。当PendingMessage的数量超过限制时,broker该如何剔除多余的消息。面向慢消费者。

MessageEvictionStrategy(消息剔除策略)

  • oldestMessageEvictionStrategy:移除旧消息,默认策略
  • oldestMessageWithLowestPriorityEvictionStrategy:移除旧消息中权重较小的消息。
  • uniquePropertyMessageEvictionStrategy:移除旧消息中带有指定property的消息。
<policyEntry topic="SKU.PRICE.>">   
    <pendingMessageLimitStrategy>  
        <constantPendingMessageLimitStrategy limit="10000"/>  
    </pendingMessageLimitStrategy>  
    <messageEvictionStrategy>  
        <uniquePropertyMessageEvictionStrategy propertyName="SKU" />  
    </messageEvictionStrategy>  
</policyEntry>  

 

上述配置,针对SKU.PRICE通道中,只保留10000个最新的消息,当容量达到阀值时,将SKU值相同的消息列表中较旧的消息移除(只保留最新的一条消息)。比如在每条消息中,都封装一个SKU(商品ID)以及其最新价格,那么通过这种策略,值保留相同SKU的最新的一个消息。 


 八. 慢速消费者策略

Broker将如何处理慢消费者。Broker将会启动一个后台线程用来检测所有的慢速消费者,并定期关闭关闭它们。 

  • abortSlowConsumerStrategy:中断慢速消费者,慢速消费者将会被关闭。

abortConnection :是否关闭连接。

maxTimeSinceLastAck:最后一个ack距离现在的时间。如果超过阈值,中断慢消费者。

<slowConsumerStrategy>    
    <abortSlowConsumerStrategy  maxTimeSinceLastAck="30000"/><!-- 30秒滞后 -->    
</slowConsumerStrategy>  

 


九. 消息转存策略(针对慢消费者)

当通道中有大量Slow Consumer时,Broker该如何优化消息的转发,以及在此情况下,“非持久化”消息达到内存限制时该如何处理。

    当Broker接受到消息后,通常将最新的消息写入内存以提高消息转发的效率,提高消息ACK的效率,减少对对底层Store的操作;如果Consumer非常快速,那么消息将会立即转发给Consumer,不需要额外的操作;但当遇到Slow Consumer时,情况似乎并没有那么美好。

    持久化消息,通常为:写入Store-->线程轮询,从Store中pageIn数据到PendingStorage-->转发给Consumer-->从PendingStorage中移除-->消息ACK后从Store中移除。

    对于非持久化数据,通常为:写入内存-->如果内存足够,则PendingStorage直接以内存中的消息转发-->如果内存不足,则将内存中的消息swap到临时文件中-->从临时文件中pageIn到内存,转发给Consumer。

PendingQueuePolicy(针对queue)

 

  1) vmQueueCursor: 将待转发消息保存在额外的内存(JVM linkeList)的存储结构中。是“非持久化消息”的默认设置,如果Broker不支持Persistent,它是任何类型消息的默认设置。有OOM风险。

    2) fileQueueCursor: 将消息保存到临时文件中。文件存储方式有broker的tempDataStore属性决定。是“持久化消息”的默认设置。

<policyEntry queue=">" producerFlowControl="true" memoryLimit="1mb">    
  <pendingQueuePolicy>
    <vmQueueCursor/>
  </pendingQueuePolicy>
</policyEntry>

    3) storeCursor: “综合”设置,对于非持久化消息,将采用vmQueueCursor存储,对于持久化消息采用fileQueueCursor。这是强烈推荐的策略,也是效率最好的策略。

<!-- persistent为true时,才能将“溢出”的非持久化消息保存为临时文件 -->  
<broker persistent="true">  
    <persistenceAdapter>  
        <!--  
        <kahaDB directory="${activemq.data}/kahadb"/>  
        -->  
        <levelDB directory="${activemq.data}/leveldb"/>  
    </persistenceAdapter>  
    <!-- 临时文件存储,默认不存储任何临时文件 -->  
    <tempDataStore>  
        <!--  
        <pListStoreImpl directory="${activemq.data}/tmp"/>  
        -->  
        <levelDB directory="${activemq.data}/leveldb/tmp"/>  
    </tempDataStore>  
    <!-- 内存限制为512M,如果超过阀值,则转存 -->  
    <policyEntry queue=">" producerFlowControl="true" memoryLimit="512mb">                 
        <pendingQueuePolicy>    
            <storeCursor>  
                <nonPersistent>  
                    <fileQueueCursor/>  
                </nonPersistent>  
            </storeCursor>  
        </pendingQueuePolicy>    
    </policyEntry>  
    <systemUsage>      
        <systemUsage sendFailIfNoSpace="true">      
           <memoryUsage>    
            <!-- 所有的通道缓存消息的总内存大小,memoryLimit作为其子模块 -->         
             <memoryUsage limit="6gb"/>   
           </memoryUsage>      
        </systemUsage>      
    </systemUsage>   
</broker> 

PendingSubscriberPolicy(针对non-durable subscriber)

支持三种策略:storeCursor, vmCursor和fileCursor。同上。

PendingDurableSubscriberPolicy(针对durable subscriber)

支持三种策略:storeDurableSubscriberCursor, vmDurableCursor和 fileDurableSubscriberCursor。

<policyEntry topic=">" producerFlowControl="false" memoryLimit="32mb">    
    <pendingSubscriberPolicy>    
        <!-- 对于非耐久的订阅者,非持久化消息: vmCursor,fileCursor -->    
         <fileCursor/>    
    </pendingSubscriberPolicy>    
    <pendingDurableSubscriberPolicy>    
        <!-- 对于耐久的订阅者,非持久化消息 -->    
        <!-- storeDurableSubscriberCursor -->    
        <!-- vmDurableCursor -->    
        <!-- fileDurableSubscriberCursor -->    
        <storeDurableSubscriberCursor/>    
    </pendingDurableSubscriberPolicy>    
</policyEntry>  

 


十. 消息传输模式转换 

    将broker接收的消息强制转换成"PERSISTENT"或者"NOT_PERSISTENT"。

<broker>  
    <plugins>  
        <!-- 将所有消息的传输模式,修改为"PERSISTENT" -->  
      <forcePersistencyModeBrokerPlugin persistenceFlag="true"/>  
    </plugins>  
</broker>  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值