ActiveMQ上具有故障转移设置的未确认消息不会重新传送给订户

时间:2017-02-07 20:47:13

标签: c# activemq nms

我在c#中实现Active MQ发布者和订阅者。我正在使用Apache.NMS.ActiveMQ .net客户端库与代理进行通信。

  <package id="Apache.NMS" version="1.7.1" targetFramework="net461" />
  <package id="Apache.NMS.ActiveMQ" version="1.7.2" targetFramework="net461" />

ActiveMQ配置了4台服务器上的故障转移设置(.225,.226,.346,.347 - IP的最后部分供参考)。经纪人网址看起来像

  

故障转移:// TCP://103.24.34.225:61616,TCP://103.24.34.226:61616,TCP://103.24.34.346:61616,TCP://103.24.34.347:61616

以下是我发布的方式

    var brokerUrl = "failover://tcp://103.24.34.225:61616,tcp://103.24.34.226:61616,tcp://103.24.34.346:61616,tcp://103.24.34.347:61616";
    var connectionFactory = new ConnectionFactory(brokerUrl);
    using (var connection = connectionFactory.CreateConnection("conn1", "conn$34"))
    {
        connection.ClientId = "TESTPUBLISHER";
        connection.AcknowledgementMode = AcknowledgementMode.ClientAcknowledge;
        connection.Start();

        var session = connection.CreateSession();
        var topic = new ActiveMQTopic("ACCOUNT.UPDATE");
        var producer = session.CreateProducer(topic);


        var msg = "43342_test"; //DateTime.Now.ToString("yyyyMdHHmmss_fff") + "-TEST";
        var textMessage = producer.CreateTextMessage(msg);

        textMessage.Properties.SetString("Topic", "ACCOUNT.UPDATE");
        textMessage.Properties.SetString("Action", "UPDATE");
        textMessage.Properties.SetString("DataContractType", "Account");

        producer.Send(textMessage, MsgDeliveryMode.Persistent, MsgPriority.Normal, new TimeSpan(0, 0, 60, 0, 0));

     }

以下是我订阅该主题的方式。设置此代码使得多个共享订户可以侦听传入消息。我被告知我必须使用虚拟主题来实现这一目标。因此,我将订户配置为使用虚拟主题,并将其托管在Windows服务项目中。我使用确认模式作为ClientAcknowledge,因此除非确认消息,否则它应该继续回来。下面的代码片段仅代表Windows服务的重要订阅者部分。

var brokerUrl = "failover://tcp://103.24.34.225:61616,tcp://103.24.34.226:61616,tcp://103.24.34.346:61616,tcp://103.24.34.347:61616"; 
IConnectionFactory factory = new ConnectionFactory(new Uri(brokerUrl));
IConnection connection = factory.CreateConnection("conn1", "conn$34"))

    connection.ClientId = "TESTSUBSCRIBER";
    connection.AcknowledgementMode = AcknowledgementMode.ClientAcknowledge;
    connection.ConnectionInterruptedListener += OnConnectionInturrupted;
    connection.ExceptionListener += OnConnectionExceptionListener;
    connection.ConnectionResumedListener += OnConnectionResumedListener;
    connection.Start();

    ISession session = connection.CreateSession(AcknowledgementMode.ClientAcknowledge);
    var queue = new ActiveMQQueue("VT.TESTSUBSCRIBER.ACCOUNT.UPDATE");
    ActiveMQTopic topic = new ActiveMQTopic();
    IMessageConsumer consumer = session.CreateConsumer(queue); 

    consumer.Listener += OnMessage;



private void OnMessage(IMessage message)
{
    var payload = ((ITextMessage)message).Text;
    Log.Info($"Received message for Client TESTSUBSCRIBER - [{payload}]");
    if(payload != "43342_test")
    {
        message.Acknowledge(); 
            Log.Info($"Message acknowledged for Client TESTSUBSCRIBER - [{payload}]");  
    }
}

private void OnConnectionResumedListener()
{
    Log.Info($"Subscriber connection resumed for Client TESTSUBSCRIBER");
}

private void OnConnectionExceptionListener(Exception exception)
{
    Log.Error(exception);
}

private void OnConnectionInturrupted()
{
    Log.Error($"Subscriber connection interrupted for Client TESTSUBSCRIBER");
}

我能够发布和订阅消息。我遇到了一个特定案例的问题。假设订户与故障转移服务器池建立了与(.225代理服务器)的连接。出版商发布了一条消息。订阅者收到了它,它正在处理中。但是由于一些服务器补丁维护,Windows服务不得不关闭。结果,与代理的订户连接断开连接。当Windows服务重新启动时,此时订阅者与故障转移池建立了与其他代理服务器(.346代理服务器)的连接。当发生这种情况时,未经确认的消息永远不会被重新传递。但是,如果我重新启动Windows服务并且运气好如果建立连接到.225代理(订户最初连接到的同一服务器),现在订阅者收到未确认的消息。

我的假设是,在故障转移设置中配置ActiveMQ时,无论来自故障转移池的哪个代理服务器都能够建立连接,它都应该始终收到未确认的消息。

在某些情况下,故障转移设置似乎正在运行。让我们假设订户已从故障转移池连接到.346代理服务器。发布者从同一个池连接到不同的代理服务器(.225代理)并发布消息,订阅者正在接收消息。这证明故障转移设置正在运行。

但是,一旦订户从代理服务器收到消息,并且如果订户在确认消息之前断开连接,则必须重新建立与同一代理服务器的连接以接收未确认的消息。这对我来说听起来不对。

Active MQ服务器设置是否需要任何其他配置才能使此用例有效?

1 个答案:

答案 0 :(得分:0)

此问题的解决方案不是在客户端,而是使用Active MQ服务器配置。

对于Producer流控制目标策略,添加ConditionalNetworkBridgeFilter并启用replayWhenNoConsumers。