ActiveMQ实践建议

消息转发模式

ActiveMQ支持两种消息转发模式:PERSISTENT(持久化)和NON_PERSISTENT(非持久化)消息。ActiveMQ默认采用的是PERSISTENT模式,消息在发送到ActiveMQ服务端后被持久化(持久化方案有多种,比如JDBC、AMQ、KahaDB、LevelDB等),如果消息服务器出现故障,可以恢复此消息并将消息传送至消费者,这种模式保证消息只被传送一次和成功使用一次。而NON_PERSISTENT模式保证消息最多被传送一次,不要求消息持久化存储,加入消息服务器出现故障,不保证消息不丢失。PERSISTENT模式有且只有一次转发消息,而NON_PERSISTENT模式最多一次转发消息。PERSISTENT消息不会丢失,并且不会被转发两次,而NON_PERSISTENT消息可能会丢失,但不会被转发两次。

在ActiveMQ中设置转发模式有两种方式,一是使用setDeliveryMode()方法,所有消息都采用这种传送模式,二是使用send()方法,为每一条消息设置传送模式。这两种方式对应javax.jms.MessageProducer接口中的三个方法:

void setDeliveryMode(int deliveryMode) throws JMSException;

void send(Message message, int deliveryMode, int priority, long timeToLive) throws JMSException;

void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive) thrwos JMSException;

使用PERSISTENT模式,表示业务场景更看重可靠性,使用NON_PERSISTENT模式,表示业务场景更看重性能。因为NON_PERSISTENT模式下,发送消息是异步的,Producer不需要等待Consumer的receipt消息,而在PERSISTENT模式下,传递消息需要先把消息存储起来,然后再传递。

消息积压

如果发送的下次没有及时消费掉,会导致消息不断积压得不到释放,从而阻塞消息队列。对于这种情况,可以配置消息过期时间和死信队列处理来预防。

消息过期

默认情况下,ActiveMQ的消息永不过期,如果业务场景需要,可以指定消息的过期时间。指定过期时间有两种方式,一是使用setTimeToLive()方法,二是使用send()方法。这两种方式对应javax.jms.MessageProducer接口中的三个方法:

void setTimeToLive(long timeToLive) throws JMSException;

void send(Message message, int deliveryMode, int priority, long timeToLive) throws JMSException;

void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive) thrwos JMSException;

如果设置timeToLive为0,表示永不过期。消息发送后,在消息过期时间到达,还没有被发送到目的地,该消息会被清除。

死信队列

一般情况下,消费消息有两种方式:一是调用MessageConsumer的receive()方法,该方法是阻塞的,接收到消息前会一直阻塞,消息返回给方法调用者后自动确认,二是通过MessageListener接口注册回调函数,有消息到达时,ActiveMQ调用接口的onMessage()方法,该方法执行完毕后消息会被确认,如果在onMessage()方法中抛出异常就不会被确认。如果该消息只有一个消费者,那么消息又会被重新获取继续抛出异常,ActiveMQ重试6次后,将这条消息丢入死信队列。

消息事务

ActiveMQ支持两种事务:JMS Transaction和XA Transaction。

JMS Transaction:使用Session接口的commit()和rollback()方法控制。

XA Transaction:为了支持两阶段提交协议,通过使用XASession与消息服务器通信来充当XAResource。

消息应答模式

对于消息消费者,除了可以使用事务的方式告知Broker消息已经处理完,更常用的是设置消息的应答模式,在javax.jms.Session接口中预定义了四种模式:

static final int SESSION_TRANSACTION = 0;// 会话事务

static final int AUTO_ACKONWLEDGE = 1;// 自动签收,当消费者通过receive()方法或者onMessage()方法成功返回消息后,session自动签收这条消息,表示消费者对消息的处理是成功的

static final int CLIENT_ACKNOWLEDGE = 2;// 客户端手动确认,必须显示调用javax.jms.Message接口中的acknowledge()方法签收消息,否则这条消息对ActiveMQ来说没有处理成功

static final int DUPS_OK_ACKNOWLEDGE = 3;// 自动批量确认,消费者按照一定策略想broker发送ack标识,表示一批消息处理完成,这种模式可能会引起消息的重复,但是可以降低Session的开销

设置消息应答模式一般是在调用Connection接口的createSession()方法创建会话对象时作为参数传进去的。

Session createSession(boolean transacted, int acknowledgeMode) throws JMSException;

一般情况下优先考虑AUTO_ACKNOWLEDGE模式,作用是延迟确认,消费者在处理完消息后不会发送ack标识,而是会缓存在Session中,等消息数量达到一定阈值,再发送一个ack指令告知一批消息已经处理完成。

消息发送优化

异步发送

ActiveMQ默认就是以异步模式发送消息的。例外情况是,在没有使用事务时,生产者以PERSISTENT模式传送消息,此时send方法是同步的,它会一直阻塞到ActiveMQ发回确认消息,并确认消息已经被存储。为了保证消息不会丢失,但会造成生产者阻塞。

生产者流量控制

如果消息积压并超过了限制大小,当生产者继续发送消息时,ActiveMQ会让生产者进入等待状态或直接抛出JMSException。

<destinationPolicy>
    <policyMap>
        <policyEntries>
            <policyEntryqueue=">" producerFlowControl="true" memoryLimit="1OOmb">
        </policyEnttries>
    </policyMap>
</destinationPolicy>

以上配置表示为所有Queue模式的队列启用生产者流量控制,限制每个队列最大存储为100MB。

消息消费优化

消息预取

为了提高消息分发效率,ActiveMQ引入了消息预取(prefetch)机制,Broker在没有收到消费者的消息反馈前会继续发新消息给它,除非消费者的消息缓存区满了,或者未收到反馈的消息数量达到了预取数量上限值,这个值是prefetchSize,对于不同类型的队列,ActiveMQ默认预取数量也不同。

转发模式 队列类型 prefetchSize
PERSISTENT Queue 1000
NON_PERSISTENT Queue 1000
PERSISTENT Topic 1000
NON_PERSISTENT Topic

32766

慢速消费者

快速生产者生产的消息不能被Consumer及时消费,导致消息积压在Broker中。这会使Broker上有大量消息驻留内存,一旦内存耗尽就会导致消息不断从文件读取到内存,然后又被交换到文件中,从而消耗磁盘IO。更严重的是会拖累生产者,导致生产者一侧阻塞,从而减缓整个MQ的工作效率。目前,对这个问题,ActiveMQ使用等待消息限制策略(Pending Message Limit Strategy)来解决。

等待消息限制策略有两种:constantPendingMessageLimitStrategy和prefetchRatePendingMessageLimitStrategy。

constantPendingMessageLimitStrategy:0:不额外增加预取数量大小;大于0:额外增加预取数量大小;-1:不增加预取数量大小也不丢弃旧的消息。

<constantPendingMessageLimitStrategy limit="50"/>

prefetchRatePendingMessageLimitStrategy:利用消费者设置的预取数量乘以其倍数等于实际的预取数量大小。

<prefetchRatePendingMessageLimitStrategy multiplier="2.5"/>

消息丢弃策略有三种:oldestMessageEvictionStrategy(丢弃最旧的消息)、oldestMessageWithLowestPriorityEvictionStrategy(丢弃最旧的且优先级最低的消息)、uniquePropertyMessageEvictionStrategy(根据自定义的属性来丢弃消息)。

消息协议

ActiveMQ支持多种消息协议,也就是activemq.xml配置文件中transportConnectors结点下的配置。可以根据需要添加相应的协议,另外可以将参数挂在uri后面。

消息持久化

ActiveMQ支持多种持久化方式,当生产者发出消息后,Broker首先将消息存储到文件、内存数据库或远程数据库等,再将消息发送给消费者,发送成功后,将消息从存储中删除,若失败继续尝试发送。

发布了172 篇原创文章 · 获赞 1 · 访问量 7143

猜你喜欢

转载自blog.csdn.net/qq_36059561/article/details/104286702
今日推荐