RabbitMQ如何决定何时删除邮件?

时间:2018-02-15 21:24:04

标签: rabbitmq high-availability queueing

我试图理解RabbitMQ中消息删除的逻辑。

我的目标是即使没有连接客户端来读取它们也会使消息持续存在,这样当客户端重新连接时,消息就会等待它们。我可以使用持久的,懒惰的队列,以便将消息持久保存到磁盘,并且我可以使用HA复制来确保多个节点获得所有排队消息的副本。

我希望使用主题或标头路由将邮件发送到两个或更多队列,并让一个或多个客户端读取每个队列。

我有两个队列,A和B,由标题交换提供。队列A获取所有消息。队列B仅获取带有“archive”标头的邮件。队列A有3个消费者阅读。队列B有1个消费者。如果B的消费者死了,但A的消费者继续确认消息,RabbitMQ会删除消息还是继续存储它们?在重新启动B之前,队列B不会有人使用它,我希望这些消息可供以后消费。

到目前为止,我已阅读了大量文档,但仍未找到明确的答案。

3 个答案:

答案 0 :(得分:1)

RabbitMQ将在确认后决定何时删除消息。

假设您有邮件发件人:

var factory = new ConnectionFactory() { HostName = "localhost", Port = 5672, UserName = "guest", Password = "guest" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
    channel.QueueDeclare(queue: "hello",
                         durable: true,
                         exclusive: false,
                         autoDelete: false,
                         arguments: null);

    string message = "Hello World!";
    var body = Encoding.UTF8.GetBytes(message);

    channel.BasicPublish(exchange: "",
                         routingKey: "hello",
                         basicProperties: null,
                         body: body);
    Console.WriteLine(" [x] Sent {0}", message);
}

这将创建一个持久的队列"你好"并发送消息" Hello World!"它。这是在向其发送一条消息后队列的样子。

enter image description here

现在让我们设置两个消费者,一个承认收到的消息,另一个消息没有。

channel.BasicConsume(queue: "hello",
                    autoAck: false,
                    consumer: consumer);

channel.BasicConsume(queue: "hello",
                    autoAck: true,
                    consumer: consumer);

如果您只运行第一个使用者,则永远不会从队列中删除该消息,因为消费者声明如果客户端手动确认消息,消息将仅从队列中消失:https://www.rabbitmq.com/confirms.html

然而,第二个消费者会告诉队列它可以安全地/立即删除它收到的所有消息。

如果您不想自动删除这些消息,则必须禁用autoAck并使用文档进行一些手动确认:

http://codingvision.net/tips-and-tricks/c-send-data-between-processes-w-memory-mapped-file(向下滚动到"手动确认")。

channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);

答案 1 :(得分:1)

简单的答案是,从一个队列消耗的消息与另一个队列中的消息无关。发布消息后,代理会根据需要将副本分发到尽可能多的队列 - 但它们是消息的真实副本,并且就代理程序而言,从那一点开始绝对不相关。

排队到持久队列的消息将一直保留,直到队列中的消费者拉出它们,并且可选地进行确认。

注意有特定的queue-level and message-level TTL settings可能会影响到这一点。例如,如果队列具有TTL,并且消费者在到期之前没有重新连接,则队列将随其所有消息一起消失。类似地,如果消息已经使用特定TTL排队(也可以将其设置为特定队列上所有消息的默认值),则一旦该TTL通过,该消息将不会传递给消费者。

次要注意如果邮件由于TTL而在队列中过期,它实际上将保留在队列中,直到下一次传递为止。

答案 2 :(得分:0)

RabbitMQ删除消息的方式有很多种。 其中一些是:

  • 来自消费者的Ack
  • 达到该队列的生存时间(TTL)。
  • 到达该队列的邮件的生存时间(TTL)。

最后两点说明RabbitMQ允许您为消息和队列设置TTL(生存时间)。 通过将 x-message-ttl 参数设置为 queue.declare ,或者通过设置 message-ttl策略。 通过将 x-expires 参数设置为 queue.declare ,或者设置过期策略,可以为给定队列设置到期时间。< / p>

队列中的消息长于配置的TTL,据说已经死了。 这里需要注意的重要一点是,路由到不同队列的单个消息可能会在不同时间死亡,有时也不会在它所驻留的每个队列中死亡。 一个队列中的邮件死亡对其他队列中同一邮件的生命没有影响