场景:有时候我们不希望消息马上被broker投递出去,而是想要消息60秒以后发给消费者,或者我们想让消息没隔一定时间投递一次,一共投递指定的次数
如何使用:
1.首先需要服务器开启定时器支持
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" schedulerSupport="true">
broker>
2.在发送端代码中设置消息的延时定时属性,部分方法示例如下:
public void send(final Serializable message)
{
MessageCreator creator = new MessageCreator()
{
@Override
public Message createMessage(Session session) throws JMSException
{
if (message instanceof String)
{
Message msg = session.createTextMessage((String) message);
//延时60秒钟投递
msg.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY,60000);
//投递10次
msg.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT,10);
return msg;
}
else
{
ObjectMessage objMessage = session.createObjectMessage();
objMessage.setObject(message);
return objMessage;
}
}
};
// 每小时发生消息投递
message.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_CRON, "0 * * * *");
CRON表达式的优先级高于另外三个参数,如果在设置了CRON的同时,也有repeat和period参数,则会在每次CRON执行的时候,重复投递repeat次,每次间隔为period。就是说设置是叠加的效果。例如每小时都会发生消息被投递10次,延迟1秒开始,每次间隔1秒
复合目的地
场景:如果需要将发往队列 A转发到队列B和主题C,就可以考虑使用复合目的地的方式,配置如下
<destinationInterceptors>
<virtualDestinationInterceptor>
<virtualDestinations>
<compositeQueue name="MY.QUEUE">
<forwardTo>
<queue physicalName="FOO" />
<topic physicalName="BAR" />
forwardTo>
compositeQueue>
virtualDestinations>
virtualDestinationInterceptor>
destinationInterceptors>
Message Group(消息分组)
可以将消息进行分组,JMS 消息属性JMSXGroupID 被用来区分message group,Message Groups特性保证所有具有相同JMSXGroupID 的消息会被分发到相同的consumer(只要这个consumer保持active),可以看作是消息的负载均衡
在一个消息被分发到consumer之前,broker首先检查消息JMSXGroupID属性。如果存在,那么broker 会检查是否有某个consumer拥有这个message group。如果没有,那么broker会选择一个consumer,并将它关联到这个message group。此后,这个consumer会接收这个message group的所有消息,直到当前Consumer被关闭或者是Message group被关闭(通过发送一个消息,并设置这个消息的JMSXGroupSeq为0)
如何使用消息分组,只需要在发送端发送代码中,指定message的JMSXGroupID即可,代码如下:
msg.setStringProperty("JMXGroupID","aClient");
JMS Selectors
消息选择器,基于消息属性对进行消息的过滤,确保客户端只能消费特定的消息
如何使用JMS Selectors,举例说明
场景:客户端监听A指定消费者去消费某一个message group(JMSXGroupID为aClinet)实现
示例代码如下:
发送端代码参见上一节Message Group消息分组
消费端queue的配置如下
<bean id="hehe" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="testQueue_One?consumer.selector=JMXGroupId='aClient'"/>
bean>
prefetch机制
ActiveMQ通过prefetch机制来提高性能,这意味这客户端的内存里可能会缓存一定数量的消息。缓存消息的数量由prefetch limit来控制。当某个consumer的prefetch buffer已经达到上限,那么broker不会再向consumer分发消息,直到consumer向broker发送消息的确认.
有如下几种方式可以使用此机制:
在客户端spring中配置ActiveMQConnectionFactory时配置如下:
<bean id="activeMQConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory" >
<property name="brokerURL">
<value>tcp://localhost:51616?jms.prefetchPolicy.all=50value>
property>
bean>
<bean id="activeMQConnectionFactory2" class="org.apache.activemq.ActiveMQConnectionFactory" >
<property name="brokerURL">
<value>tcp://localhost:61616?jms.prefetchPolicy.queuePrefetch=1value>
property>
bean>
或者针对某一个queue或者topic配置如下:
<bean id="hehe" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue?consumer.prefetchSize=10"/>
bean>
prefetch size的缺省值如下:
持久化queue:1000条
非持久化queue: 1000条
持久化topic:100条
非持久化topic: 无限制
消息游标
游标的作用是在于标识下一次将要读取的数据的位置mq支持三种游标
Store-based游标
目前是mq默认使用的游标,可以适用于大部分的场景:
快消费时(有可用内存):store-based将直接将消息存储并发送至dispatch,流程图如下:
慢消费(当无可用内存):这时,消息不再直接发往dispatch,而是先存储在文件中,由pending cursor去取文件中的数据,发送给dispatch,流程图如下:
VM游标
消息接收后,首先完成消息存储的工作,然后直接把消息存放在pendingCursor,发送给目标队列
注意:vm方式建议在内存足够大的情况下使用,而且vm方式不适合处理慢消费,vmCursor+非持久时,直接变成一个内存MQ,为了防止内存溢出,在消息积压到指定数量的时候,PFC会阻止生产消息。
File游标
包含vm的处理方式,如果broker内存已经耗尽,则会将消息先存在临时文件中,当需要将消息发送到dispatch中去时,则使用pending cursor去读取一批临时文件中的数据
注意这里当内存不够用时,实际上会操作2次文件读写,性能相对比较差,适用场景是在,存储比较慢,消费比较快的情况下
如何使用游标
需要在服务端配置如下:
topic目的地配置
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry topic=">" >
<pendingSubscriberPolicy>
<vmCursor>vmCursor> <!—指定为vm游标-- >
pendingSubscriberPolicy>
policyEntry>
policyEntries>
policyMap>
destinationPolicy>
queue目的地配置
<policyEntry queue=">" >
<pendingQueuePolicy>
<vmQueueCursor>vmQueueCursor> <!—指定为vm游标-- >
pendingQueuePolicy>
policyEntry>
动态修改配置文件
在5.9.0版本之后,引入了动态修改broker的activemq.xml配置文件功能,需要做如下配置即可:
"http://activemq.apache.org/schema/core" start="false" ... >
"1000" />
...
plugins:支持添加插件
runtimeConfigurationPlugin:允许动态修改配置文件的插件,checkPeriod表示割多少时间去检查一次
注意:
start=”false” 这个属性表示spring不会自动的将broker启动,会首先保证插件初始化。
支持动态修改的属性有