使用Apache Camel和ActiveMQ时如何处理系统崩溃

时间:2019-12-11 06:19:43

标签: java spring-boot apache-camel activemq

我有带有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;
    }
}

2 个答案:

答案 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文件非常相似:

Blueprint Camel Route

在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。

您应该看到两个提交是背对背的。这提供了一个非常小的窗口,在该窗口中失败可能导致重复的邮件传递。

我强烈建议尽可能从我的例子开始。即使很小的偏差也会产生非常意外的结果。