我有带有ActiveMQ的Apache Camel来进行大小为1000的批处理。我的理解是,Apache骆驼将从队列中检索1000个数据并进行处理,一旦处理完成,它将推送到TO队列。我的问题是,如果处理这些数据的系统在推送TO队列之前崩溃了,将会发生什么情况。此数据是保留在ActiveMQ中还是永久丢失。
在没有Apache骆驼的情况下,我们可以为侦听器配置不同的确认模式,例如CLIENT_ACKNOWLEDGE。
Apache骆驼中是否有类似的东西。下面是我的JMS Config类
public class JMSConfig {
private Environment env;
public JMSConfig(Environment env) {
this.env = env;
}
@Bean
public ConnectionFactory connectionFactory() {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
return connectionFactory;
}
@Bean
public JmsTransactionManager geJmsTransactionManager(final ConnectionFactory connectionFactory) {
JmsTransactionManager jmsTransactionManager = new JmsTransactionManager();
jmsTransactionManager.setConnectionFactory(connectionFactory);
return jmsTransactionManager;
}
@Bean
public JmsComponent createJmsComponent(final ConnectionFactory connectionFactory, final JmsTransactionManager jmsTransactionManager) {
JmsComponent jmsComponent = JmsComponent.jmsComponentTransacted(connectionFactory, jmsTransactionManager);
return jmsComponent;
}
}
答案 0 :(得分:0)
使用“大小为1000的批处理”我并没有真正理解您的意思,但是听起来您消耗了1000条消息,将它们提交给代理,然后继续进行处理。这就是问题的根源。
如果您想避免丢失消息,则必须使用来自代理的事务处理,并且在“安全”之前不要提交消息。
最简单的例子:
from("activemq:queue:myInput")
.to("activemq:queue:myOutput")
如果JMS组件已正确配置为使用事务处理,则即使您在处理过程中杀死了Camel应用程序,您也不会在此路由中丢失消息。
这是因为代理将邮件保留到提交为止。并且Camel能够在将消息交给myOutput
之前提交消息。因此,这是完全安全的。
但是,当您使用1000条消息时,我假设它们在使用后即被提交,因此在代理上被删除。因此,它们不再存在于任何地方,而仅存在于Camel应用程序的内存中。如果出现故障,它们将丢失。
请注意,您不需要Spring TxManager就可以使用事务处理。查看Camel docs about transacted JMS,特别是有关交易DMLC的要点(Camel JMS使用Springs MessageListenerContainer)。这减少了您的配置,并且您也不需要将您的骆驼路线标记为已交易。
顺便说一句,如果您的路由包含诸如聚合器之类的有状态组件,则事情会变得复杂,因为这些组件引入了新的交易边界。
答案 1 :(得分:0)
早上好
一段时间以来,我一直在想回答您的问题,对此致歉意。
我将与本地JMS事务讨论Dups-OK消息传输。这意味着JMS发送和接收会话将使用本地JMS事务。这两个独立的本地事务将由JTA事务管理器同步。对于JTA同步事务,必须在确认“获取”之前确认对“ put”的提交。
但是首先,在这种情况下使用ActiveMQs消息预取有一些想法。默认情况下,当在会话上进行recieve()调用时,A-MQ开箱即用将“预取” 1000条消息。这假定客户端代码将使消息侦听器处于打开状态并消耗所有1000条消息。例如,如果客户端代码仅读取1条消息,然后关闭会话,则必须将999条消息返回到源队列。或者,如果发生了某些不良情况,则事务可能会失败并破坏预取。
我可以继续详细讨论这个主题,但是只知道Spring JMS代码在事务性Camel路由和消息预取中不能很好地工作,因此在示例中将禁用预取。请注意,消息预取是一种性能优化,因此在没有预取的情况下使路由正常工作是一件好事。然后,您可能会发现消息预取可以提高性能,但具有非常不希望的副作用。
您没有提到您的平台,我将讨论一个Blueprint XML文件。这与标准的Camel / Spring XML文件非常相似:
在OSGi平台上工作时,默认情况下我将Aries安装为Platform Transaction Manager,而Aries是JTA事务管理器。例如,如果您使用的是Spring Boot,则可能需要包含以下启动程序:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-narayana</artifactId>
</dependency>
为了具有JTA PlatformTransactionManager(在这种情况下为Arjuna)。不要实例化JmsTransactionManager并将其分配为PlatformTransactionManager。
查看代码,请注意:
<property name="brokerURL" value="tcp://10.0.0.170:61616?jms.prefetchPolicy.all=0"/>
这将禁用消息预取。
请注意,我没有明确引用任何事务管理器。设置:
<property name="transacted" value="true"/>
将为您创建一个JmsTransactionManager。
然后一行:
<transacted id="trans"/>
将启动JTA事务上下文。这两个本地JMS事务将同步,您可能会收到重复的消息,但不会丢失消息。
添加一些日志记录:
<logger name="org.apache.camel" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.springframework.jms.connection.JmsTransactionManager" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.apache.activemq.TransactionContext" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
或者也许:
<logger name="com.arjuna" level="TRACE" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
如果您正在使用Arjuna。
您应该看到两个提交是背对背的。这提供了一个非常小的窗口,在该窗口中失败可能导致重复的邮件传递。
我强烈建议尽可能从我的例子开始。即使很小的偏差也会产生非常意外的结果。