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

RabbitMQ-具有手动确认的非阻塞消费者,rabbitmq,Rabbitmq,我刚刚开始学习RabbitMQ,如果我的问题很基本,请原谅我 我的问题实际上与这里发布的问题相同: 然而,经过调查,我发现手动确认会阻止其他消费者从队列阻塞状态获取消息。我想知道怎样才能预防它。下面是我的代码片段 rabbit提供了一个基础设施,其中一个使用者不能锁定/阻止使用同一队列的其他消息使用者。 您面临的行为可能是以下几个问题的结果: 您没有在频道上使用自动确认模式这一事实会导致您遇到这样的情况:一位消费者接收了该消息,但仍然没有发送批准(基本确认),这意味着计算仍在进行中,使用者可

我刚刚开始学习RabbitMQ,如果我的问题很基本,请原谅我

我的问题实际上与这里发布的问题相同:

然而,经过调查,我发现手动确认会阻止其他消费者从队列阻塞状态获取消息。我想知道怎样才能预防它。下面是我的代码片段


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

  • 您没有在频道上使用自动确认模式这一事实会导致您遇到这样的情况:一位消费者接收了该消息,但仍然没有发送批准(基本确认),这意味着计算仍在进行中,使用者可能无法处理此消息,因此应将其保留在兔子队列中,以防止消息丢失(管理协商中的消息总量不会改变)。在此期间(从获取消息到客户端代码,直到发送明确的确认),消息被标记为被特定客户端使用,其他消费者无法使用。但是,如果有更多的消息需要接收,这不会阻止其他使用者从队列中接收其他消息

    重要事项:为防止手动确认信息丢失,请确保 若要在处理故障时关闭通道或发送nack,请发送至 防止应用程序从队列中获取消息的情况, 处理失败,已从队列中删除,消息丢失

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


  • 希望这有帮助。

    我修改了从队列中获取消息的方式,似乎阻塞问题已经解决。下面是我的代码

        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);
        }
    

    我感谢你的任何意见和建议。谢谢

    我相信,因为我没有调用QOS,而且队列中几乎没有消息,所以代理只向一个消费者发送消息。谢谢你指给我看。然而,当我添加QOS时,我注意到在我发送并运行单个消费者的10条消息中,只有一半是确认消息。消息1、3、5、7、9仅为确认。对此有什么想法吗?请注意您的基本拒绝-您有多个true,可能这就是导致以下情况的原因?我修改并删除了拒绝代码,但仍然无法正常工作。我看到了一些迭代BasicConsume返回值的代码。现在,我将继续使用BasicGet。将消息发布到exchange,而不是直接发布到队列,然后每个消费者使用一个队列可以解决这个问题。
        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);
        }