ActiveMQ中Producer特性详解

前言

    从本文中你可以得到如下几个问题的解答:

    1) 设定消息的时间戳有什么作用

    2) 消息的timeToLive与过期原理

    3) Producer同步、异步发送消息,以及调优

    4) 消息priority与顺序,以及其中的误解。

 

    Producer作为ActiveMQ的消息发送端,是开发工程师经常需要面对的,我们需要多了解一些Producer的特性,以便开发出更高效的应用。

 

    如下为典型的代码示例:

String brokerUrl = "tcp://localhost:61616";
String queueName = "test-queue";
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerUrl);
Connection connection = factory.createConnection();
//ActiveMQFactory.createConnection(brokerUrl);
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);  
Destination queue = session.createQueue(queueName);  
MessageProducer producer = session.createProducer(queue);
for(int i=0; i<5; i++){
	producer.send(session.createTextMessage("Hello,ActiveMQ!!"));
}
//....
connection.close();

 

    一个Producer的创建过程中,会涉及到brokerUrl、destinationUri、Connection、session、ACK模式主要的几个概念。它们都有一些隐藏的“秘密”值得我们去探索。此外producer复杂发送消息,还有很多与消息有关的特性需要注意。

 

1. disableMessageID

    在发送消息时,是否禁用MessageID属性。JMS的标准中并没有约定消息的ID是由Producer创建还是由Broker创建,禁用MessageID在一定程度上会减少网络开支,事实上这个属性在ActiveMQ没有任何意义。无论任何时候,Producer总会在发送消息之前,为Message生成全局唯一的MessageID。(JMSMessageID,由producerId + “:” +  sequenceNumber组成)

 

2. disableMessageTimestamp

    是否禁用消息时间戳。时间戳用来表示消息被producer发送的时间(非broker接收的时间),通常此timestamp和TTL一起决定消息是否已经过期;消费者也可以根据此timestamp获知消息发送的时间,以及在selector中使用timestamp来过滤过期或者较旧的消息等。

 

    如果属性值为true,则在发送消息时会将消息的JMSTimestamp属性值设为为当前时间的时间戳;否则JMSTimestamp属性值将保持默认(0)。

 

  • 可以在brokerUrl中设定全局的默认值:  "tcp://localhost:61616?jms.disableTimeStampsByDefault=true"

  • messageProducer.setDisableMessageTimestamp(boolean)

    此选项只会影响到消息在producer端创建的时间,在ActiveMQ中,Message被额外的增加了2个属性,开发者可以获得更多关于消息流动的相关时间信息(ActiveMQMessage):

 

  • JMSActiveMQBrokerInTime: 表示消息被broker接收的时间戳

  • JMSActiveMQBrokerOutTime: 消息离开broker即将传送给consumer的时间戳。

3. defaultTimeToLive

    消息的存活时间。用来约束消息的过期时间,即JMSExpiration属性。注意timeToLive属性只会在DisableMessageTimestamp=false的情况下才有意义。

    JMSExpiration = timestamp + timeToLive。timeToLive默认值为0,即表示消息永不过期。只有当timeToLive值 > 0时,JMSExpiration属性才会被赋值。

 

  • messageProducer.setTimeToLive(long)

  • messageProducer.send(Message message, int deliveryMode, int priority, long timeToLive): 可以在消息发送时,为当前消息设定ttl。

    如果开发者使用TTL来判定消息的过期,那么就首先需要确保Producer、broker两者的系统时间要尽可能的一致,此外我们还需要Consumer也尽可能的和broker的时间保持一致。如果Produer的时间相对broker而言落后太多,有可能导致发送的消息直接被broker抛弃(broker接收消息后会检测是否过期,对于已经过期的消息则直接抛弃),消费者将无法获得相关消息。

 

    Broker将会在接收Producer消息时,以及将消息发送给Consumer之前都会检测消息是否过期,判断过期的方法也就是根据JMSExpiration和当前时间戳比较。如果消息过期,将会把消息发送到DLQ(Dead Letter Qeue)中,那么事实上此消息不会被Consumer消费;不过我们可以通过特殊的方式检测这些DLQ,比如侦听"ActiveMQ.DLQ"队列。由此可见,在使用TTL的时候,如果Producer与Broker的系统时间差距较大,将会导致消息“丢失”。

 

    不过,还有一种“可怕”情况,如果broker端对DLQ使用Discard策略或者Broker没有开启DLQ相关策略,这些过期的消息可能将不复存在。

 

  <destinationPolicy>
   <policyMap>
     <policyEntries>
       <policyEntry queue=">" topic=">">
         <deadLetterStrategy>
           <sharedDeadLetterStrategy processExpired="false" />
         </deadLetterStrategy>
		 <!-- discard all -->
		 <!--
		 <discardingDeadLetterStrategy />
		 -->
       </policyEntry>
     </policyEntries>
   </policyMap>
  </destinationPolicy>
 

 

4. alwaysSyncSend/useAsyncSend

    用来设定producer(或者session)发送消息的方式:同步/异步。

 

    alwaysSyncSend表示消息将总会被同步发送(request<->response),即消息通过底层transport链接发送之后,将会阻塞直到收到broker端的ProducerAck或者sentTimeout。同步发送,是一种担保能力强但发送效率较低的方式,如果消息发送失败,client端可以立即获得异常。如果alwaysSyncSend值为true,则producer将使用同步发送所有消息(同时忽略useAsyncSend选项)

 

    useAsyncSend表示消息可以被异步发送(oneway),异步发送并不是消息在client缓存起来,而是消息也将立即被transport发送给broker,只是不会阻塞等待broker的ACK。消息发送给broker之后,producer.send方法将会立即返回。异步发送,通常配合broker端“Flow Control”手段使用,它可以最大化produer端的发送效率。我们通常在消息量比较密集的情况下使用异步发送,它可以很大的提升Producer性能;不过这也带来了额外的问题,就是需要消耗较多的Client端内存,同时也会导致broker端性能消耗增加;此外它不能有效的确保消息的发送成功。在useAsyncSend的情况下,客户端需要容忍消息丢失的可能。

    

//brokerUrl中指定异步/同步发送
jms.alwaysSyncSend=false&jms.useAsyncSend=true

    1) 当alwaysSyncSend=false时,对于“NON_PERSISTENT”(非持久化)消息将使用“异步发送”;对于非持久化消息,使用异步发送是最佳的选择,我们通常使用这种手段调优。

 

    2) 当alwaysSyncSend=false时,如果指定了useAsyncSend=true,都将采用异步发送,包括“PERSISTENT”类型的消息,也将使用异步发送。

    3) 当alwaysSyncSend=false时,无论如何,在事务中的消息,都将使用异步发送。

    4) 当alwaysSyncSend=true时,所有类型的消息,都将采用同步发送。

    5) 总结:默认情况下,非持久化消息、事务内的消息均采用异步发送;对于持久化消息,则采用同步发送。

 

5. sendTimeout

    消息发送最大阻塞(等到ACK)时间。这个参数和syncSend方式配合使用,在同步发送方式中,send方法将会阻塞直到broker反馈ACK,不过这种阻塞的时长无法预期,我们需要使用sendTimeout来设定最大的阻塞时间,如果阻塞超时,将会抛出RequestTimedOutIOException。此值默认为0,表示永不超时。

 

  • 在brokerUrl中设定

//在brokerUrl中指定,单位:毫秒
jms.sendTimeout=30000
  • connection.setSendTimeout(long) 

    此外需要注意,如果指定了sendTimeout值 >0,无论何时,所有的消息都将同步发送。(忽略alwaysSyncSend、useAsyncSend、消息持久化方式等)。如果sendTimeout <0,则效果和=0一致。

 

6. socket优化

    如果我们的brokerUrl中,使用了TCP/UDP等transport,我们还可以直接对socket进行优化,这些参数需要再brorkerUrl中指定:

 

tcp://localhost:61616?socket.sendBufferSize=1024

 

7. windowSize(异步发送)

    窗口尺寸,用来约束在异步发送时producer端允许积压的(尚未ACK)的消息的尺寸,且只对异步发送有意义。每次发送消息之后,都将会导致memoryUsage尺寸增加(+message.size),当broker返回producerAck时,memoryUsage尺寸减少(producerAck.size,此size表示先前发送消息的大小)。可以通过如下2种方式设置:

  • 在brokerUrl中设置: "tcp://localhost:61616?jms.producerWindowSize=1048576",这种设置将会对所有的producer生效。

  • 在destinationUri中设置: "test-queue?producer.windowSize=1048576",此参数只会对使用此Destination实例的producer失效,将会覆盖brokerUrl中的producerWindowSize值。

     此值越大,意味着消耗Client端的内存就越大。

 

    至此我们已经清楚,任何发送到broker端的消息,broker总会在存储成功后回传ProducerAck信息,并且在ACK中包含消息的size。当producer发送消息时,会首先检测memoryUsage中是否有足够的空间(根据message.size判断),如果空间足够,则消息正常发送;否则将会阻塞,直到收到producerACK且memoryUsage空间释放足够多。(注意,对于持久化消息,只要broker存储消息成功即立即发送ProcuerAck)

 

    这是一个非常重要而且有效的调优参数之一;它在producer端消息发送比较密集时,或者producer发送速率与consumer消费速度失衡严重时,对维护broker实例性能稳定具有重要意义。比如,当producer短时间内大批量发送消息,而consumer消费速度相对较低时,会对broker端的存储造成巨大冲击,在极端情况下,可能导致OOM或者broker宕机。所以,我们通常开启此参数,且指定相对合理的值。

 

    仅仅在producer指定windowSize,可以在Client端避免这些问题,不过这只是一个方面;但是从全局来看,还不够全面,我们还需要在broker端使用“Flow Control”策略来避免上述情况的发生。不过对于"持久化"类型的消息,当broker存储成功之后,总是立即发送ack,所以我们不需要担心会带来潜在的危险。因为“windowSize”、“Flow Control”通常是针对“非持久化”消息。

 

    “Flow Control”通常称为“流量控制”,它的核心理念就是“按需交付”。如果每个Producer指定的windowSize为64M,但是我们有10个这样的producer,那么意味着broker端在最坏的情况下,需要承载640M数据,不过很不幸的是broker上可供cache的空间只有512M,那么此后broker可能因为内存不足而强制挂起Producer的物理连接(connection),从而导致在connection上无法继续发送任何消息。这会引入另外一个问题,当connection上还有当前通道(Queue或者Topic)的consumer时,会带来死锁;这导致consumer的ACK无法发送-->进而导致消息继续消费,以致于形成“消息无法消费”“也无法发送”的死锁情况。所以通常情况下,我们不能让Consumer和Producer共享一个物理Connection。

 

  “Flow Control”所能做的就是:当broker内存不足时,让producer暂停一下,直到消息消费之后腾出足够的空间。可以让消息密集发送时,broker能够协调Producer发送的“频率”,同时确保自己的性能处于可控范围。

 

<policyEntry queue=">" producerFlowControl="true" memoryLimit="32mb">  
  <!-- only for queue -->
  <!-- topic is very different from it -->
  <pendingQueuePolicy>
    <!-- non_persistent: use "vmQueueCursor",persistent: use "fileQueueCursor" -->
    <storeCursor/>
	<!-- also can do this -->
	<!--
	<storeCursor>
		<nonpersistent>
			<vmQueueCursor/>
		</nonpersistent>
	</storeCursor>
	-->
  </pendingQueuePolicy>
</policyEntry>

 

    上述配置描述的是,对于任意一个queue都使用32m内存保存非持久化消息,如果超过限制,将阻塞Producer链接。不过强制挂起Producer似乎有些过于粗暴,我们可以增加如下配置,当borker内存不足时,向producer发送一个异常,此时producer可以通过捕获异常来“暂停与重试(sleep一会再发送)”或者提交事务(如果事务中有大量消息且消息为持久化类型的)。

 

<systemUsage>
 <systemUsage sendFailIfNoSpace="true">
   <memoryUsage>
     <memoryUsage limit="512mb"/>
   </memoryUsage>
 </systemUsage>
</systemUsage>

 

8. Transaction

    producer端可以使用事务来实现多条消息的“原子性”。据上所述,事务中的消息,都会采用asyncSend方式发送,对于broker而言将会把当前producer事务中的消息cache在内存中,直到事务提交。 

 

//如果使用事务,其中transacted=true,ackMode = Auto_ACK,事实上ackMode对producer并无意义。
connection.createSession(boolean transacted, int acknowledgeMode)

 

    对于producer而言,事务并没有特别需要注意的地方,无论是持久化/非持久化,建议不要在一个事务中同时发送过多的消息,此外建议设定windowSize,即“事务” + “windowSize”是推荐的一种高效的方式。

 

    开发者需要再合适的时机,调用session.commit()方法来提交事务,不过需要注意session非线程安全,建议在事务类型下,每个producer独占一个session已防止多线程(多producer)提交的时机不同而造成混乱。 

 

9. Priority(权重)与消息传送顺序

    我们可以在发送消息时,指定消息的权重,broker可以建议权重较高的消息将会优先发送给Consumer。在某些场景下,我们通常希望权重较高的消息优先传送;不过因为各种原因,priority并不能决定消息传送的严格顺序(order)。

 

    JMS标准中约定priority可以为0~9的数值,值越大表示权重越高,默认值为4。不过activeMQ中各个存储器对priority的支持并非完全一样。比如JDBC存储器可以支持0~9,因为JDBC存储器可以基于priority对消息进行排序和索引化;但是对于kahadb/levelDB等这种基于日志文件的存储器而言,priority支持相对较弱,只能识别三种优先级(LOW: < 4,NORMAL: =4,HIGH: > 4)。在broker端,默认是不支持priority排序的,我们需要手动开启:

 

<policyEntry queue=">" prioritizedMessages="true"/>

 

    一旦开启了此属性,此后消息存储时,将会按照prioprity的倒序索引化消息(比如kahadb B+Tree,此后priority将作为索引的一部分)。此后broker从存储器中获取消息时,权重较高的消息将会被优先获取;对于JDBC等其他存储器,可能在获取消息时,按照priority作为排序列来筛选消息。

 

    我们首先简单的描述一下,消息在broker端pending的过程,这涉及到prefetch机制以及消息是否持久化等方面的问题。在broker端,为了优化Consumer消费的效率,通常开启prefetch策略,即从通道中(Queue/Topic)批量加载多条消息,这些消息可能来自内存(非持久化),也可能来自存储文件(持久化消息,或者非持久化消息被swap到临时文件中);borker会为每个Consumer创建一个基于内存的pending buffer,用来保存即将发送给Consumer的消息列表。当buffer中的消息被Consumer消费之后,将会从内存或者文件中继续加载多条消息,然后再根据需要将一定量的消息放入到pending buffer中。由此可见,我们只能保证每次prefetch的消息列表是按照priority排序的,但是有可能在buffer中的消息还没有发送之前,会有更高优先级的消息被写入文件或内存,事实上这已经不能改变消息发送的顺序了;因为我们无法在全局范围内,保证Consumer即将消费的消息是权重最高的!!

 

    不过对于“非持久化”类型的消息(如果没有被swap到临时文件),它们被保存在内存中,它们不存在从文件Paged in到内存的过程,因为可以保证优先级较高的消息,总是在prefetch的时候被优先获取,这也是“非持久化”消息可以担保消息发送顺序的优点。

 

     Broker在收到Producer的消息之后,将会把消息cache到内存,如果消息需要持久化,那么同时也会把消息写入文件;如果通道中Consumer的消费速度足够快(即积压的消息很少,尚未超过内存限制,我们通过上文能够知道,每个通道都可以有一定的内存用来cache消息),那么消息几乎不需要从存储文件中Paged In,直接就能从内存的cache中获取即可,这种情况下,priority可以担保“全局顺序”;不过,如果消费者滞后太多,cache已满,就会触发新接收的消息直接保存在磁盘中,那么此时,priority就没有那么有效了。

 

    在Queue中,prefetch的消息列表默认将会采用“轮询”的方式(roundRobin,注意并不是roundRobinDispatch)[备注:因为Queue不支持任何DispatchPolicy],依次添加到每个consumer的pending buffer中,比如有m1-m2-m3-m4四条消息,有C1-C2两个消费者,那么: m1->C1,m2->C2,m3->C1,m4->C2。这种轮序方式,会对基于权重的消息发送有些额外的影响,假如四条消息的权重都不同,但是(m1,m3)->C1,事实上m2的权重>m3,对于C1而言,它似乎丢失了“顺序性”。

 

//参见org.apache.activemq.broker.region.Queue
//doActualDispatch方法
//伪代码,描述

//pendingList: 从store中PageIn 的消息列表,亟待发送
Iterator it = pendingList.iterator();
//为了当前Page的消息发送,创建一个消费者列表的copy
//每个Queue都持有目前所有的消费者列表。
//在broker端,Subscription负责和Consumer客户端通讯
List<Subscription> copyConsumers = new ArrayList<Subscription>(this.allSubscriptions);
Set<Subscription> fullConsumers = new HashSet<Subscription>();
while(it.hasNext()){
    Message mx = it.next();
    for(Subscription consumer : copyConsumers){
		if(fullConsumers.contains(consumer)){
			break;//如果当前consumer亟待确认的消息已经超过了prefetch
		}
		//如果当前consumer中的pendingBuffer没有满
		if(!consumer.isFull()){
			it.remove();
			consumer.dispatch(mx);//异步发送消息,addBuffer
			if(!strictOrderDispatch){
				//如果不是严格顺序发送
				//对consumers按照权重排序
				//权重高的consumer,将会被有限填充buffer
				//当权重相同时,将会按照它们最后发送消息的ID,倒序排列
				//即消息ID较小的,将会优先获取新消息。
				Collections.sort(this.allSubscritpions);
				//重建copy
				copyConsumers = new ArrayList<Subscription>(this.allSubscriptions); 
			}
		}else{
			fullConsumers.add(consumer);
		}
			
}
if(!pendingList.isEmpty()) {
	//剩余的消息,将会被cache起来,继续轮训上述过程
}

 

 

    为了让priority的消息更加具备顺序性,我们可以通过如下配置来调整:

     

//queue or topic
<policyEntry queue=">" strictOrderDispatch="true" />

 

    strictOrderDispatch“严格顺序转发”,这是区别于“轮询”的一种消息转发手段;不过不要误解它为“全局严格顺序”,它只不过是将prefetch的消息依次填满每个consumer的pending buffer。比如上述例子中,如果C1-C2两个消费者的buffer尺寸为3,那么(m1,m2,m3)->C1,(m4)->C2;当C1填充完毕之后,才会填充C2。由此这种策略可以保证buffer中所有的消息都是“权重临近的”、有序的。(需要注意:strictOrderDispatch并非是解决priority消息顺序的问题而生,只是在使用priority时需要关注它)。

 

    对于Queue而言,仅仅使用strictOrderDispatch并不能完全解决顺序问题,它可能是相对高效但是比较粗略的方式;如果需要严格保证有序性,我们需要按照如下方式配置:

 

<policyEntry queue=">" prioritizedMessages="true" useCache="false" expireMessagesPeriod="0" queuePrefetch="1" />

 

    useCache=false来关闭内存,强制将所有的消息都立即写入文件(索引化,但是会降低消息的转发效率);queuePrefetch=1来约束每个consumer任何时刻只有一个消息正在处理,那些消息消费之后,将会从文件中重新获取,这大大增加了消息文件操作的次数,不过每次读取肯定都是priority最高的消息。[对于broker而言,如果指定了prioritizedMessage将在存储时就根据消息的权重建立索引顺序,在内存中使用PrioritizedPendingList保存消息;否则将使用OrderedPendingList]

 

    “strictOrderDispatch”也适用于Topic,broker可以保证所有Subscriber获得的消息的顺序是一致的。不过Topic支持DispatchPolicy,但是不支持"strictOrderDispatch"属性,这个与Queue有所不同。

 

<policyEntry topic=">">
	<dispatchPolicy>
		<strictOrderDispatchPolicy />
	</dispatchPolicy>
</policyEntry>

 

 

    此外,对于Consumer而言,我们需要关注一个参数:messagePrioritySupported;它表示consumer端是否支持权重排序,默认为true,即当Consumer客户端使用了prefetchSize时,将会对这些已经到达Session但还没有转发给Consumer的消息列表,按照权重排序。我们可以通过这种方式开启:

 

//brokerUrl中
jms.messagePrioritySupported=true

 

    如果你关闭了此选项,那么需要注意,当高权重的消息因为消费异常而重发时,将不能被优先消费。 

 

10. Producer消息传送模型

 

 

 

11. 如何提升Producer端消息发送效率?

    在某些场景下,我们的Producer的个数是非常有限的,可能只有几个,比如基于Queue的“订单接入网关”(生成订单原始信息并负责传递),但是相应的Consumer的个数相对较多,在整体上Producer效能小于Consumer。还有一些场景,Producer的数量非常,消息量也很大,但是Consumer的个数或者效能相对较低,比如“用户点击流”、“用户消息Push系统”等。

 

    究竟该如何提高消息发送的效率,参考上文,几个因素值得我们考虑:

    1) 消息持久化:持久化类型的消息,对broker端性能消耗远远大于非持久化类型;这归结于ActiveMQ本身对持久化消息确保“最终一致性”,持久化意味着“消息不丢失”(无论过期,还是DLQ),即当broker接收到消息后需要一次强制性磁盘同步(fsync)[备注:不过基于日志的存储器kahadb/levelDB提供延迟写入的特性,如果开启延迟写入,将会在broker物理失效时有丢失数据的潜在风险];对于Consumer在消费消息后,也会触发磁盘写入(通常为标记消息已消费,或者移除消息的相关索引信息;这个过程通常是延迟写入);此外,通常broker端还会开启相关的“过期消息检测”线程,将存储器中的数据载入内存并检测,这个过程也是内存、磁盘IO消耗的。由此可见,持久化类型的消息从始至终,都在“拖累”着系统的性能和吞吐能力。

 

     这就要求,开发者根据实际需要定夺消息的传输模式(持久化、非持久化),对于数据可靠性要求较低,容忍数据在极端情况下丢失的场景中,我们需要果断的使用NON_PERSISTENT。

 

    2) 消息属性: 通过Producer发送的消息(Message)中,除了消息本身的负荷体之外(content),还有大量的JMS属性和Properties可以设置,比如timestamp、priority等。因为JMS中,支持对JMS属性和properties使用selector,那么这些内容将会加大和复杂化message header,我们尽可能的在properties中携带更少、更小的数据。此外,我们还不能通过Message传递较大的文本、流数据,尽管activeMQ支持这些特性,但是它会对broker带来更多消息存储、控制成本,事实上,较大数据的传递,使用activeMQ是不理智的。

    此外,我们需要慎重的使用Priority,这会对底层的存储器带来额外的性能开支。

 

    3) 异步发送:如果消息是非持久化的,或者Session是基于事务的,建议开发者不要关闭异步发送;这是提升Producer发送效率的重要的策略。设定合适的windowSize,开启Broker端“Flow Control”等,这既可以提高Produer发送效率,还能避免因Producer数据过大造成Broker不稳定的问题。

 

    4) 事务:对于Producer而言,使用事务并不会消耗Broker太多的性能,主要是会占用内存,所有未提交的事务消息,都会保存在内存中,有些基于日志的存储存储器,事务类型的持久化消息暂存在额外的文件中,直到日志提交或者回滚后清除。所以,Producer端不要在事务中,积压太多的消息,尽可能早的提交事务。

 

    5) 提升Consumer消费速率,无论是Queue还是Topic,快速的Consumer,无疑是提升整体效能的最好的手段,开发者需要在Consumer个数和消费耗时等多个方面权衡,尽可能通过良好的架构设计,让Consumer的消费速率和Producer的生产速率保持同步。

 

    6) 选择合适的存储器: activeMQ目前支持JDBC/kahadb/LevelDB三种主要的存储器。JDBC主要面向基于RDBMS方向,通常如果消息不仅面向ActiveMQ,还可能被用于第三方平台的操作,JDBC的特点就是透明度高,可扩展方案较多(但扩展成本较高)。kahadb和LevelDB,同属于日志存储 + BTree索引,性能很好,对于消息较多(单位尺寸较小),消费速度较快的应用,是最好的选择,这两种存储器也是最常用的,其中LevelDB是被推荐使用的。

 

12. ActiveMQ Producer与Spring代码样例

    1) MessageProducerClient.java

public class MessageProducerClient {
	
    private ActiveMQConnectionFactory connectionFactory;
    
    private String destination;
    
    private MessageProducer producer;
    
    private ActiveMQConnection connection;
    
    private Session session;
    
    private int deliveryMode = DeliveryMode.PERSISTENT;
    
    public String getDestination() {
		return destination;
	}


	public void setDestination(String destination) {
		this.destination = destination;
	}

	public void setDeliveryMode(int deliveryMode) {
		this.deliveryMode = deliveryMode;
	}


	public void setConnectionFactory(ActiveMQConnectionFactory connectionFactory) {
		this.connectionFactory = connectionFactory;
	}
	
	public void init() throws Exception{
		connection = (ActiveMQConnection)connectionFactory.createConnection();
		connection.start();
		session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
		Destination physical = ActiveMQDestination.createDestination(destination, ActiveMQDestination.QUEUE_TYPE);
		producer = session.createProducer(physical);
		producer.setDeliveryMode(deliveryMode);
	}

    public void send(String text) throws Exception{
    	TextMessage message = session.createTextMessage(text);
    	producer.send(message);
    }
    
    public void send(Message message) throws Exception{
    	producer.send(message);
    }
    
    
    public void close(){
    	try{
    		connection.close();
    	}catch(Exception e){
    		e.printStackTrace();
    	}
    }
}

    2) spring配置

<bean id="activeMQConnectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory">
	<property name="brokerURL" value="tcp://localhost:61616"/>
	<property name="userName" value=""/>
	<property name="password" value=""/>
	<property name="sendTimeout" value="3000" />
</bean>

<bean id="orderMessageProducerClient" class="com.test.common.MessageProducerClient" init-method="init" destroy-method="close">
	<property name="connectionFactory" ref="activeMQConnectionFactory"></property>
	<property name="destination" value="queue://order.queue"></property>
</bean>

  

 

 

结语:

    我们从大体上剖析了和Producer、Message有关的几个重要属性,开发者需要再合适的场景中使用它们。如果本文有错误之处,敬请各位不吝赐教,批评斧正。谢谢!

    有关消息权重部分,[请参阅]

    1. ActiveMQMessageProducer

    2. TransportConnection

    3. Broker,BrokerService,PolicyEntry

    4. TransactionBroker,TransactionStore

    5. PrioritizedPendingList

    

ActiveMQ消息传送机制以及ACK机制详解 AcitveMQ是作为一种消息存储和分发组件,涉及到client与broker端数据交互的方方面面,它不仅要担保消息的存储安全性,还要提供额外的手段来确保消息的分发是可靠的。一. ActiveMQ消息传送机制 Producer客户端使用来发送消息的, Consumer客户端用来消费消息;它们的协同中心就是ActiveMQ broker,broker也是让producer和consumer调用... 阅读详情

相关推荐

解决Android 14兼容性问题:NDK中arm64-v8a的正确配置方法

本文详细解析Android 14系统架构变化对NDK开发的影响,重点介绍arm64-v8a架构的正确配置方法。针对常见的兼容性问题如so库缺失、ABI不匹配等提供解决方案,并分享性能优化与自动化测试实践,助力开发者高效适配Android 14设备。

algae的博客 1222

消息生产者(Message Producer)是消息队列或消息中间件中的一个关键角色

消息生产者(Message Producer)是消息队列或消息中间件中的一个关键角色。其主要职责是创建并发送消息到消息队列或主题中。

[Blog][Domain] programb.blog.youkuaiyun.com 941

ARM双核锁步DCLS Lockstep技术研究(FPGA实现)

基于《Applying Dual-Core Lockstep in Embedded Processors to Mitigate Radiation-induced Soft Errors》文章总结 RISC-V双核锁步DCLS Lockstep技术参考之前文章: RISC-V双核锁步DCLS Lockstep技术总结_远古架构师alanwu的博客-优快云博客https://blog.youkuaiyun.com/heyuming20062007/article/details/123329537ARM+RIS

heyuming20062007的博客 8727

ActiveMq之消息发送(MessageProducer)-yellowcong

MessageProducer,是用来发送消息的,用来设定消息的优先级,签收的模式,以及消息的存活时间的设定。

4275

华为设备有关用户名密码的策略配置

命令用来开启对密码进行复杂度检查功能,设备默认已经是开启状态。1、密码长度大于等于12位,含数字大小写字母和特殊符号。2、设置密码更换周期为90天。取值范围8-16,默认长度为8位。登录失败后锁定时间大于15分钟。3、登录失败次数小于5次。4、登录超时30分钟以内。

简单的创作,希望可以帮助到跟我一样的学习者! 7840

企业微信API实战:解密external_userid的跨应用一致性管理

本文深入探讨企业微信API中external_userid的跨应用一致性管理问题,解析其本质及在不同应用场景下的ID不一致挑战。通过ID转换与统一管理方案,结合unionid实现跨应用客户数据整合,提供实战代码示例和架构设计,助力企业构建高效的客户管理系统。

weixin_29258297的博客 637

ActiveMQ入门

前言:最近在公司用到了activeMq接收消息,从网上查了资料老忘,所以总结一下。 第一章 前言 第二章 三种模式 2.1 点对点 2.2 队列 2.3 虚拟队列 第三章 ...

仰望星空 597

STK与Matlab连接报错?手把手教你解决mexConnect函数执行问题(附完整避坑指南)

本文针对STK与Matlab连接时常见的“mexConnect函数执行”报错,提供了完整的诊断与解决方案。文章深入剖析了错误根源在于路径冲突或文件损坏,并手把手指导用户通过定位STK连接器文件、正确配置Matlab路径(包括使用addpath命令)以及执行初始化测试三步走策略,彻底解决问题。同时附上版本兼容性检查、安装避坑指南及构建稳健工作流的建议,帮助用户建立可靠的STK-Matlab联合仿真环境。

yolo5detector的博客 472

【转】ActiveMQ中Producer特性详解

http://shift-alt-ctrl.iteye.com/blog/2034440 (laoda.toutiao.im)   前言     从本文中你可以得到如下几个问题的解答:     1) 设定消息的时间戳有什么作用     2) 消息的timeToLive与过期原理     3) Producer同步、异步发送消息,以及调优     4) 消息priority与顺序,以及...

缘自天方的博客 279

vietjetair 航空的webpack多参数生成学习

工作内不是特别多,居安思危,有一个抓机票信息的公司面试前竟然需要做面试题,这就是一个题。看了下,有点麻烦,webpack 最初不得要领,看了下资料,找了个框架,练了两个简单的,搞这个吧。入库需要自己找,有几个参数不是明文的,算法不是很复杂,位置不太好找。整体难度一般。

liu_yueyang的博客 1510

安装Openclaw[本地自动化AI助手]至windows【WSL2模式】系统 Openclaw for Windows

摘要:OpenClaw最佳兼容OpenAI系列模型,推荐使用ChatGPT API(需Auth鉴权),避免K*mi等模型导致的信用卡风险。Windows系统需满足WSL2支持条件(Win11或Win10 1903+版本)。安装需导入自签名根证书或跳过浏览器安全警告,通过离线包部署WSL发行版。使用时通过clawtoken命令获取网关认证令牌,并在浏览器完成设备配对。提供代购ChatGPT Plus账号服务(¥140/月),详细操作指南需加微信群获取文件。(150字)

qq_27246521的博客 456

JMS & ActiveMQ 简介

一、JMS简介 全称:Java Message Service 中文:Java消息服务 JMS是Java的一套API标准,最初的目的是为了使应用程序能够访问现有的MOM系统(MOM是Message Oriented Middleware的英文缩写,指的是利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。);后来被许多现有的MOM供应商采用,并实现为MOM系统。...

Zllvincent的博客 7030

爬取Unsplash高清壁纸:Python爬虫实战教程(最新技术)

在当今数字化时代,高清壁纸已经成为人们个性化设备的重要元素。Unsplash作为全球最知名的免费高质量图片网站,汇集了数百万张由全球摄影师贡献的高清图片。然而,Unsplash官网的下载方式需要手动操作,对于需要批量下载壁纸的用户来说效率较低。本文将带你深入探索如何使用Python爬虫技术高效爬取Unsplash高清壁纸,从基础到进阶,全面掌握图片爬取的核心技术。Unsplash成立于2013年,是一个完全免费的图片分享平台。高质量内容:所有图片均由专业摄影师上传,分辨率普遍达到4K以上免费商用。

2201_76125261的博客 936

ActiveMQ专题13—— ActiveMQ高级特性

ActiveMQ高级特性: 异步投递 延迟投递和定时投递 分发策略 消息重试机制 死信队列 异步投递 ActiveMQ支持同步,异步两种发送的模式将消息发送到broker,模式的选择对发送延时有巨大的影响。producer能达到怎么样的产出率(产出率=发送数据总量/时间)主要受发送延时的影响,使用异步发送可以显著提高发送的性能。 ActiveMQ默认使用异步发送的模式\color{red}ActiveMQ默认使用异步发送的模式ActiveMQ默认使用异步发送的模式,除非明确指定使用同步发送的方式或者在未

xiaozhegaa的博客 1178

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

java连接activemq_ActiveMQ入门系列一:认识并安装ActiveMQ(Windows下)

一、什么是ActiveMQ度娘给出的定义:Apache ActiveMQ是Apache软件基金会所研发的开放源代码消息中间件;由于ActiveMQ是一个纯Java程序,因此只需要操作系统支持Java虚拟机,ActiveMQ便可执行。ActiveMQ的官网打出的标语(如上图):Flexible & Powerful Open Source Multi-Protocol Messaging大...

weixin_29304021的博客 425

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

activemq

Producer客户端使用来发送消息的, Consumer客户端用来消费消息;它们的协同中心就是ActiveMQ broker,broker也是让producer和consumer调用过程解耦的工具,最终实现了异步RPC/数据交换的功能。随着ActiveMQ的不断发展,支持了越来越多的特性,也...

chouyandeng3609的博客 92

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

ActiveMQ讯息传送机制以及ACK机制详解

【http://www.ylzx8.cn/ruanjiangongcheng/software-architecture-design/11922.html】 AcitveMQ:消息存储和分发组件,涉及到client与broker端数据交互的方方面面,它不仅要担保消息的存储安全性,还要提供额外的手段来确保消息的分发是可靠的。 【ActiveMQ消息传送机制】Producer客户端用来发送...

weixin_30300225的博客 96
上一篇: ActiveMQ消息传送机制以及ACK机制详解
下一篇: ActiveMQ中Consumer特性详解与优化
iteye_19607
博客等级 码龄8年 34粉丝 198原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值