RabbitMQ - 具有手动确认功能的非阻塞消费者

时间:2014-06-10 01:53:45

标签: rabbitmq

我刚开始学习RabbitMQ,请原谅我,如果我的问题非常基础。

我的问题实际上与此处发布的问题相同: RabbitMQ - Does one consumer block the other consumers of the same queue?

然而,经过调查,我发现手动确认会阻止其他消费者从队列中获取消息 - 阻塞状态。我想知道如何防止它。以下是我的代码段。

...

var message = receiver.ReadMessage();
Console.WriteLine("Received: {0}", message);

// simulate processing
System.Threading.Thread.Sleep(8000);

receiver.Acknowledge();

public string ReadMessage()
{

   bool autoAck = false;
   Consumer = new QueueingBasicConsumer(Model);
   Model.BasicConsume(QueueName, autoAck, Consumer);
   _ea = (BasicDeliverEventArgs)Consumer.Queue.Dequeue();
   return Encoding.ASCII.GetString(_ea.Body);
}

public void Acknowledge()
{

   Model.BasicAck(_ea.DeliveryTag, false);
}

2 个答案:

答案 0 :(得分:2)

我修改了从队列中获取消息的方式,似乎修复了阻塞问题。以下是我的代码。

    public string ReadOneAtTime()
    {
        Consumer = new QueueingBasicConsumer(Model);
        var result = Model.BasicGet(QueueName, false);
        if (result == null) return null;
        DeliveryTag = result.DeliveryTag;
        return Encoding.ASCII.GetString(result.Body);
    }

    public void Reject()
    {
        Model.BasicReject(DeliveryTag, true);
    }

    public void Acknowledge()
    {
        Model.BasicAck(DeliveryTag, false);
    }

回到我原来的问题,我添加了QOS并注意到其他消费者现在可以获得消息。然而有些人未被承认,我的程序似乎挂断了。代码更改如下:

    public string ReadMessage()
    {
        Model.BasicQos(0, 1, false); // control prefetch
        bool autoAck = false;
        Consumer = new QueueingBasicConsumer(Model);
        Model.BasicConsume(QueueName, autoAck, Consumer);

        _ea = Consumer.Queue.Dequeue();
        return Encoding.ASCII.GetString(_ea.Body);
    }

    public void AckConsume()
    {
        Model.BasicAck(_ea.DeliveryTag, false);
    }

    In Program.cs
    private static void Consume(Receiver receiver)
    {
        int counter = 0;
        while (true)
        {
            var message = receiver.ReadMessage();
            if (message == null)
            {
                Console.WriteLine("NO message received.");
                break;
            }
            else
            {
                counter++;
                Console.WriteLine("Received: {0}", message);
                receiver.AckConsume();
            }
        }

        Console.WriteLine("Total message received {0}", counter);
    }

我感谢任何意见和建议。谢谢!

答案 1 :(得分:0)

嗯,兔子提供的基础设施,一个消费者无法锁定/阻止使用同一队列的其他消息使用者。 您面临的行为可能是以下几个问题的结果:

  1. 您没有在频道上使用自动确认模式这一事实会导致您遇到一个消费者接收消息而仍未发送批准(基本确认)的情况,这意味着计算仍在进行中消费者有可能无法处理此消息,并且应将其保留在兔子队列中以防止消息丢失(消息总量不会在管理消耗中发生变化)。在此期间(从获取消息到客户端代码,直到发送显式确认),消息被标记为由特定客户端使用,并且不可供其他消费者使用。但是,如果需要更多的苔藓,这并不妨碍其他消费者从队列中获取其他消息。

    重要提示:使用手动确认来确保消息丢失 在处理故障时关闭通道或发送nack到 防止应用程序从队列中获取消息的情况 无法处理,从队列中删除,并丢失了消息。

  2. 其他消费者无法使用相同队列的另一个原因是QOS - 通道的参数,您可以在其中声明应将多少消息推送到客户端缓存以改善出列操作延迟(使用本地缓存)。你的代码示例缺少这部分代码,所以我只是在猜测。在这种情况下,QOS可能非常大,以至于服务器上的所有消息都被标记为属于一个客户端,而其他任何客户端都无法接受任何这些消息,就像我已经描述的手动确认一样。
  3. 希望这有帮助。