在ActiveMQ中,消息分为持久化消息和非持久化消息。消息的持久化特性,通过producer.setDelivery()方法来设置。
MessageProducer producer = session.createProducer(destination);
//DeliveryMode.NON_PERSISTENT--持久化
//DeliveryMode.NON_PERSISTENT--非持久化
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
消息的发送,分为同步发送(sync)和异步发送(async)。接下来我们来详细讲解ActiveMQ消息的发送策略。
消息的同步和异步发送,是ActiveMQ的两个特性。这两个特性主要是在消息发送端---至--->Broker之间的一个概念。ActiveMQ支持同步、异步两种模式,来讲消息发送至Broker上。
同步:同步发送过程中,发送者发送一条消息会阻塞,直到Broker反馈给一个确认消息,表示消息已经被Broker处理。这个机制提供了消息的安全性保障,但是由于是阻塞的操作,【会影响到消息从生产者发送到Broker上的性能】
异步:异步发送的过程中,发送者不需要等待Broker提供反馈,所以性能相对较高。但是可能会出现消息丢失的情况。所以使用异步发送的前提,是在【允许出现数据丢失的情况下使用】
策略选择:异步发送或者同步发送,在不同的情况下有不同的策略。那就是持久化策略和非持久化策略。在默认情况下,【非持久化消息是异步发送的;非持久化消息 && 非事务模式下是同步发送的】,但是在开启事务的情况下,消息都是异步发送的。因为异步发送的效率会比同步发送性能更快,所以【在发送持久化消息的时候,尽量去开启事务会话】
如何设置同步/异步发送:除了持久化消息和非持久化消息的同步和异步特性外,我们还可以通过以下三种方式来设置异步发送:
//1.直接在brokerUrl中设置
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.204.201:61616?jms.useAsyncSend=true");
//2.直接在connectionFactory中设置属性
((ActiveMQConnectionFactory)connectionFactory).setUseAsyncSend(true);
//3.直接在当前connection设置属性
((ActiveMQConnection)connection).setUseAsyncSend(true);
流程解析
1. producer.send( )方法,默认是异步发送,在发送过程中,会判断producerWindow是否有空间;
2. 如果说没有空间,则它会处于阻塞(Blocking)状态;
3. 如果空间被释放,当消息被Broker端确认后,producerWindow窗口会递减,此时,在Broker端会发送一个onProducerACK消息,producerWindow会递减消费后的消息的大小;
4. 此时Blocking状态,又会恢复为一个可运行状态;
5. 如果producerWindow存在空间大小的话,会再次判断是不是异步发送。其实在步骤1中就已经有一个判断了。默认是异步发送的,只有异步发送,才会存在producerWindow这个概念;
6. 如果是异步发送,会增加producerWindow的空间大小;
7. 再会通过传输层,去发送消息至Broker上.至此,异步发送结束;
8. 同步发送的情况下,会经过传输层,此时会处于阻塞(Blocking)状态;
9. 消息最终,还是会发送至Broker,最后Broker再返回相关数据。
ProducerWindowSize概念,是producer允许积压的消息的大小,仅针对异步情况下有效。通过producerWindowSize能够控制待确认的消息的大小。
异步发送情况下,producer每发送一个消息,都会统计一下发送的字节数,当字节数达到ProducerWindowSize值时,需要等待broker的确认,确认当前剩余的空间是否做够接收新消息(大小),然后才能继续发送。
如何设置消息发送窗口(ProducerWindowSize)的大小?
1.通过jms.producerWindowSize=xxx来设置
在brokerUrl中设置:"tcp://192.168.204.201:61616?jms.producerWindowSize=xxx",这种设置将会对所有的producer生效。
2.也可以destinationUri中通过producer.windowSize=xxx设置
在destinationUri中设置:session.setQueue("myQueue?producer.windowSize=xxx"),这种设置只对使用此Destionation实例的producer生效,这这个设置将会覆盖brokerUrl中设置的producerWindowSize值。注意:此值越大,意味着消耗的内存也会越大。
如需了解源码,请点击:ActiveMQ消息发送【源码分析】
END