生存时间和过期
本指南中涵盖的关键主题包括
- RabbitMQ 支持的队列 TTL 和消息 TTL 功能概述
- 每个队列在队列级别定义的消息 TTL
- 每个消息由发布者定义的 TTL
- 消息 TTL 和死信
- 追溯应用的消息 TTL
- 队列 TTL(队列过期)
生存时间功能
使用 RabbitMQ,您可以为消息和队列设置 TTL(生存时间)参数或策略。顾名思义,TTL 指定消息和队列的“生存期”。
消息 TTL 决定消息在队列中可以保留多长时间。如果消息在队列中的保留时间超过了队列的消息 TTL,则该消息将过期并被丢弃。
“丢弃”表示消息不会传递给任何已订阅的消费者,并且无法通过直接应用于队列的basic.get
方法访问。消息 TTL 可以应用于单个队列、一组队列或按消息逐个应用。
TTL 也可以设置在队列上,而不仅仅是队列内容。此功能可以与自动删除队列属性一起使用。通常,仅对瞬态(非持久)经典队列设置队列 TTL(过期)才有意义。流不支持过期。
仅当队列未使用时,队列才会在一段时间后过期(如果队列有在线消费者,则表示正在使用)。
TTL 设置也可以由操作员策略强制执行。
队列中的每个队列消息 TTL
可以通过使用策略设置message-ttl
参数或在声明队列时指定相同的参数来为给定队列设置消息 TTL。
如果消息在队列中保留的时间超过配置的 TTL,则该消息被称为过期。请注意,路由到多个队列的消息可以在每个驻留的队列中以不同的时间过期,或者根本不过期。一条消息在一个队列中的过期不会影响同一消息在其他队列中的生命周期。
服务器保证不会使用basic.deliver
(发送给消费者)或在轮询消费者响应(在basic.get-ok
响应中)中发送过期的消息。
此外,服务器将尝试在消息 TTL 到期时或稍后删除消息。
TTL 参数或策略的值必须为非负整数(等于或大于零),以毫秒为单位描述 TTL 时间段。
因此,值为 1000 表示添加到队列的消息将在队列中保留 1 秒,或直到它被传递给消费者。该参数可以是 AMQP 0-9-1 类型short-short-int
、short-int
、long-int
或long-long-int
。
使用策略定义队列的消息 TTL
要使用策略指定 TTL,请将键“message-ttl”添加到策略定义中
rabbitmqctl |
|
---|---|
rabbitmqctl(Windows) |
|
这将对所有队列应用 60 秒的 TTL。
在声明期间使用 x-arguments 为队列定义消息 TTL
此 Java 示例创建一个队列,其中消息最多可以保留 60 秒
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-message-ttl", 60000);
channel.queueDeclare("myqueue", false, false, false, args);
C# 中的相同示例
var args = new Dictionary<string, object>();
args.Add("x-message-ttl", 60000);
model.QueueDeclare("myqueue", false, false, false, args);
可以将消息 TTL 策略应用于已包含消息的队列,但这涉及一些注意事项。
如果消息重新入队(例如,由于使用了具有重新入队参数的 AMQP 方法,或由于通道关闭),则会保留其原始过期时间。
将 TTL 设置为 0 会导致消息在到达队列时过期,除非它们可以立即传递给消费者。因此,这为immediate
发布标志提供了一种替代方案,RabbitMQ 服务器不支持该标志。与该标志不同,不会发出任何basic.return
,如果设置了死信交换机,则消息将被送入死信。
发布者中的每个消息 TTL
可以通过在发布消息时设置expiration
属性来按消息指定 TTL。
expiration
字段的值以毫秒为单位描述 TTL 时间段。与x-message-ttl
相同的约束适用。由于expiration
字段必须是字符串,因此代理将(仅)接受数字的字符串表示形式。
当同时指定每个队列和每个消息 TTL 时,将选择两者之间较小的值。
此示例使用RabbitMQ Java 客户端发布一条消息,该消息最多可以在队列中保留 60 秒
byte[] messageBodyBytes = "Hello, world!".getBytes();
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
.expiration("60000")
.build();
channel.basicPublish("my-exchange", "routing-key", properties, messageBodyBytes);
C# 中的相同示例
byte[] messageBodyBytes = System.Text.Encoding.UTF8.GetBytes("Hello, world!");
IBasicProperties props = model.CreateBasicProperties();
props.ContentType = "text/plain";
props.DeliveryMode = 2;
props.Expiration = "60000";
model.BasicPublish(exchangeName,
routingKey, props,
messageBodyBytes);
每个消息 TTL 和死信
仲裁队列
当仲裁队列中的消息到达队列头部时,将把过期的消息送入死信。
经典队列
经典队列在以下几种情况下将过期的消息送入死信
- 当消息到达队列头部时
- 当队列收到影响它的策略更改通知时
追溯应用的消息 TTL(到现有队列)
对已应用追溯消息 TTL 的队列(当它们已包含消息时),将在发生特定事件时丢弃消息。
仅当过期的消息到达队列头部时,它们才会被实际丢弃(标记为删除)。消费者不会收到过期的消息。请记住,消息过期和消费者传递之间可能存在自然的竞争条件,例如,消息可以在写入套接字后但到达消费者之前过期。
设置每个消息 TTL 时,过期的消息可能会排在未过期的消息后面,直到后者被消费或过期。因此,此类过期消息使用的资源不会被释放,并且将在队列统计信息(例如队列中的消息数)中进行计数。
在追溯应用每个消息 TTL 策略时,建议让消费者在线以确保消息更快地被丢弃。
鉴于每个消息 TTL 设置对现有队列的行为,当需要删除消息以释放资源时,应改用队列 TTL(或队列清除或队列删除)。
队列 TTL
TTL 也可以设置在队列上,而不仅仅是队列内容。此功能可以与自动删除队列属性一起使用。
通常,仅对瞬态(非持久)经典队列设置 TTL(过期)才有意义。流不支持过期。
仅当队列未使用时,队列才会在一段时间后过期(如果队列有在线消费者,则表示正在使用)。
可以通过将x-expires
参数设置为queue.declare
或设置expires
策略来为给定队列设置过期时间。这控制队列在自动删除之前可以保持不使用多长时间。未使用表示队列没有消费者、队列最近未重新声明(重新声明会续订租约)以及basic.get
在至少过期时间段内未被调用。例如,这可用于 RPC 样式的回复队列,其中可以创建许多可能永远不会被清空的队列。
服务器保证如果队列至少在过期时间段内未使用,则该队列将被删除。对于队列在过期时间段过去后将被删除的及时性,不作任何保证。
x-expires
参数或expires
策略的值以毫秒为单位描述过期时间段。它必须是正整数(与消息 TTL 不同,它不能为 0)。因此,值为 1000 表示 1 秒内未使用的队列将被删除。
使用策略定义队列的队列 TTL
以下策略使所有队列在上次使用后 30 分钟过期
rabbitmqctl |
|
---|---|
rabbitmqctl(Windows) |
|
在声明期间使用 x-arguments 为队列定义队列 TTL
此 Java 示例创建一个队列,该队列在 30 分钟未使用后过期。
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-expires", 1800000);
channel.queueDeclare("myqueue", false, false, false, args);