RabbitMQ 如何决定何时删除一条消息?

How does RabbitMQ decide when it is time to delete a message?

我正在尝试了解 RabbitMQ 中消息删除的逻辑。

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

我希望使用主题或 header 路由将消息发送到两个或多个 queue,并让一个或多个客户端阅读每个 queue。

我有两个 queue,A 和 B,由 header 交易所提供。 Queue A 获取所有消息。 Queue B 只收到 "archive" header 的消息。 Queue A 有 3 个消费者阅读。 Queue B 有 1 个消费者。如果B的消费者死了,但是A的消费者继续确认消息,RabbitMQ会删除消息还是继续存储消息? Queue 在 B 重新启动之前,B 不会让任何人使用它,我希望这些消息仍然可用以供以后使用。

到目前为止我已经阅读了一堆文档,但仍然没有找到明确的答案。

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" 并将消息 "Hello World!" 发送给它。这是向队列发送一条消息后的样子。

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

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

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

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

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

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

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

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

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

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

请注意 有特定的 queue-level and message-level TTL settings 可能会影响此。例如,如果队列有一个 TTL,并且消费者在它过期之前没有重新连接,那么队列将连同它的所有消息一起消失。类似地,如果一条消息已使用特定 TTL 入队(也可以将其设置为特定队列中所有消息的默认值),则一旦该 TTL 通过,该消息将不会传递给消费者。

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

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

  • 消费者确认后
  • Time-to-live(TTL) 该队列已达到。
  • Time-to-live(TTL) 该队列上的消息已到达。

最后两点指出 RabbitMQ 允许您为消息和队列设置 TTL(Time-to-live)。 可以通过将 x-message-ttl 参数设置为 queue.declare 或通过设置 message-ttl 政策。 可以通过将 x-expires 参数设置为 queue.declare 或通过设置 政策到期

在队列中的时间超过配置的 TTL 的消息被认为是死的。 这里要注意的重要一点是,路由到不同队列的单个消息可能会在不同时间死亡,或者有时永远不会在它所在的每个队列中死亡。 一个队列中消息的死亡对其他队列中同一消息的生命没有影响