当前位置: 首页 > 知识库问答 >
问题:

HA故障转移期间ActiveMQ Artemis发布消息丢失

劳豪
2023-03-14

我使用ActiveMQ Artemis 2.17.0,我希望避免在故障转移期间生成器中丢失消息。

通过捕获ActiveMQunblockedException并再次发送消息来处理Artemis主动到被动切换期间的消息发布丢失。代理被配置为主动/被动HA共享存储。主动节点配置在host1和被动节点配置在host2中。Url为:

(tcp://host1:61616,tcp://host2:61616)?ha=true&reconnectAttempts=-1&blockOnDurableSend=false

我们使用Spring 4.2.5和CachingConnectionFactory作为连接工厂。

我使用以下代码发送消息:

private void sendMessageInternal(final ConnectionFactory connectionFactory, final Destination queue, final String message)
        throws JMSException {

    try (final Connection connection = connectionFactory.createConnection();) {
        connection.start();
        try (final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                final MessageProducer producer = session.createProducer(queue);) {
            final TextMessage textMessage = session.createTextMessage(message);
            producer.send(textMessage);
        }

    } catch (JMSException thr) {
        if (thr.getCause() instanceof ActiveMQUnBlockedException) {
            // consider as fail-over disconnection, send message again.
        } else {
            throw thr;
        }
    }
}

在host1机器中,Artemis部署为master-node1。在host2机器中,Artemis作为slave-node2部署。下面是模拟故障转移的步骤

  1. Node1和node2已启动
  2. Node1作为实时服务器启动,node2作为备份服务器启动
  3. 杀死node1,node2成为实时服务器
  4. 客户端发布代码抛出ActiveMQunblockedException并处理以再次发送消息
  5. 再次启动node1。node1成为实时服务器,node2再次成为备份
  6. 客户端发布代码未引发ActiveMQunblockedException和消息丢失。

在第3步中获得以下错误堆栈。(被杀死的node1和node2成为实时服务器)。

javax.jms.JMSException: AMQ219016: Connection failure detected. Unblocking a blocking call that will never get a response
    at org.apache.activemq.artemis.core.protocol.core.impl.ChannelImpl.sendBlocking(ChannelImpl.java:540)
    at org.apache.activemq.artemis.core.protocol.core.impl.ChannelImpl.sendBlocking(ChannelImpl.java:434)
    at org.apache.activemq.artemis.core.protocol.core.impl.ActiveMQSessionContext.sessionStop(ActiveMQSessionContext.java:470)
    at org.apache.activemq.artemis.core.client.impl.ClientSessionImpl.stop(ClientSessionImpl.java:1121)
    at org.apache.activemq.artemis.core.client.impl.ClientSessionImpl.stop(ClientSessionImpl.java:1110)
    at org.apache.activemq.artemis.jms.client.ActiveMQSession.stop(ActiveMQSession.java:1244)
    at org.apache.activemq.artemis.jms.client.ActiveMQConnection.stop(ActiveMQConnection.java:339)
    at org.springframework.jms.connection.SingleConnectionFactory$SharedConnectionInvocationHandler.localStop(SingleConnectionFactory.java:644)
    at org.springframework.jms.connection.SingleConnectionFactory$SharedConnectionInvocationHandler.invoke(SingleConnectionFactory.java:577)
    at com.sun.proxy.$Proxy5.close(Unknown Source)
    at com.eu.amq.failover.test.ProducerNodeTest.sendMessageInternal(ProducerNodeTest.java:133)
    at com.eu.amq.failover.test.ProducerNodeTest.sendMessage(ProducerNodeTest.java:110)
    at com.eu.amq.failover.test.ProducerNodeTest.main(ProducerNodeTest.java:90)

共有1个答案

范书
2023-03-14

您得到的ActiveMQunblockedException来自Spring对javax.jms.Connection#Stop的调用。和发送信息无关。当收到此特定异常时,重新发送消息可能会导致重复的消息。

最终,您的问题与设置BlockonDurableSend=false直接相关。这告诉客户“开火并忘记”。换句话说,客户机不会等待代理的响应来确保消息真正成功。这种缺乏等待的情况增加了吞吐量,但降低了可靠性。

如果您真的想减少潜在的消息丢失,您有两个主要的选择。

使用CompletionListener。这将允许您保留BlockonDurableSend=false,但是如果发送消息时出现问题,应用程序仍然会得到通知,尽管信息将异步提供。这个特性是在JMS2中专门为这类场景添加的。有关更多细节,请参见JavaDoc。

 类似资料:
  • 我试图创建一个简单的redis高可用性设置与1主,1从和2哨兵。 当从故障转移到时,该设置工作正常。当恢复时,它将自己正确地注册为新的主服务器的从服务器。 但是,当作为主服务器关闭时, 不能作为主服务器返回。的日志进入循环,显示: 每个复制文档都声明: 自Redis4.0以来,当一个实例在故障转移后被提升为master时,它仍然能够与旧master的从机执行部分重新同步。 但日志似乎显示了另一种情

  • null 当我使用Ctrl-C停止活动服务器时,从服务器报告的而断开连接,这是正确的,但是备份服务器没有更改其状态,也没有侦听端口61617。那么我在配置中做错了什么呢? 实时服务器配置: 备份服务器配置:

  • 我们使用MQ作为传递消息的主要路径。这是我们的制度运作不可或缺的一部分。消息代理有时会失败,所有相关的队列也会随之失败。在camel中,有没有一种方法可以启动故障切换,并在其启动时恢复到主故障切换?

  • 我们正在设计一个解决方案,它将使用JMS使用来自IBMMQ的消息。计划是使用WASLiberty,所以JMS是首选技术。我们将创建Message-Drive bean来侦听MQ队列中的消息。 我们也在考虑WAS自由和开放自由。 这里的诀窍是,我们必须使用故障转移来实现它,这样,如果一台服务器出现故障,另一台服务器将继续自动使用MQ中的消息。比如在主动/被动机制中。 我知道需要安装MQ适配器,因为它

  • 我正在尝试用6台机器实现一个Redis集群。我有一个由六台机器组成的流浪集群: 运行redis服务器 我编辑了上述所有服务器的/etc/redis/redis.conf文件,添加了这个 然后我在六台机器中的一台上运行了这个程序; Redis集群已启动并运行。我通过在一台机器上设置值手动检查它显示在其他机器上。 我的问题是,当我关闭或停止任何一台主机上的redis server时,整个集群都会停止运

  • 我使用的是Apache Artemis V2.12.0,在两个VM中启动了两个broker实例 broker.xml(myhost1)[myhost2的broker.xml与此类似,只是我使用的端口是61616] 步骤2:java客户机开始向代理发送消息 步骤3:从myhost1的控制台,我看到推送到队列中的消息 步骤4:停止myhost1中的代理实例 客户端代码执行日志消息:当客户端启动时,my