生存时间 (Time-to-Live) 和过期
本文件指南涵盖的关键主题包括:
- RabbitMQ 支持的队列 TTL 和消息 TTL 功能概述
- 按队列定义的 队列级别的消息 TTL
- 由发布者定义的 消息 TTL
- 消息 TTL 和死信
- 消息 TTL 的追溯应用
- 队列 TTL(队列过期)
生存时间 (TTL) 功能
使用 RabbitMQ,您可以为消息和队列设置 TTL(生存时间)参数或策略。顾名思义,TTL 指定了消息和队列“存活”的时间段。
消息 TTL 决定了消息在队列中可以保留多长时间。如果消息在队列中的保留时间超过了队列的消息 TTL,则该消息将过期并被丢弃。
“丢弃”意味着消息不会被发送到任何订阅的消费者,也不会通过直接应用于队列的 basic.get 方法进行访问。消息 TTL 可以应用于单个队列、一组队列,或者逐条消息地应用。
TTL 也可以设置在队列本身上,而不仅仅是队列的内容。此功能可以与自动删除队列属性一起使用。通常,仅为临时(非持久性)的经典队列设置队列 TTL(过期)才有意义。Streams 不支持过期。
当队列未使用时,队列才会在一段时间后过期(如果队列有在线消费者,则认为队列被使用)。
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 (bash)
- 使用 rabbitmqadmin (bash)
- 使用 rabbitmqctl (PowerShell)
- 使用 rabbitmqadmin (PowerShell)
rabbitmqctl set_policy TTL ".*" '{"message-ttl":60000}' --apply-to queues
rabbitmqadmin policies declare \
--name "TTL" \
--pattern ".*" \
--definition '{"message-ttl":60000}' \
--apply-to "queues"
rabbitmqctl.bat set_policy TTL ".*" "{""message-ttl"":60000}" --apply-to queues
rabbitmqadmin.exe policies declare ^
--name "TTL" ^
--pattern ".*" ^
--definition "{""message-ttl"":60000}" ^
--apply-to "queues"
这会将 TTL 设置为 60 秒,应用于所有队列。
在声明时使用 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 策略,但这涉及 一些注意事项。
如果消息被重新排队(例如,由于使用了带有 requeue 参数的 AMQP 方法,或者由于通道关闭),其原始过期时间将得以保留。
将 TTL 设置为 0 会导致消息在到达队列时过期,除非它们能够立即传递给消费者。因此,这提供了 immediate 发布标志的替代方案,而 RabbitMQ 服务器不支持该标志。与该标志不同,不会发出 basic.return,并且如果设置了死信交换,则消息将被死信。
发布者中的按消息 TTL
可以通过在发布消息时设置 expiration 属性 来按消息指定 TTL。
expiration 字段的值以毫秒为单位描述 TTL 周期。与 x-message-ttl 具有相同的限制。由于 expiration 字段必须是字符串,因此代理将(仅)接受数字的字符串表示形式。
当同时指定了按队列 TTL 和按消息 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 和死信
仲裁队列
Quorum 队列在过期消息到达队列头部时将其死信。
经典队列
经典队列在以下几种情况下死信过期消息:
- 当消息到达队列头部时
- 当队列收到影响它的策略更改通知时
按消息 TTL 的追溯应用(应用于现有队列)
当向现有队列追溯应用按消息 TTL 时,队列将在特定事件发生时丢弃消息。
只有当过期消息到达队列头部时,它们才会被实际丢弃(标记为删除)。消费者不会收到过期消息。请记住,消息过期和消费者投递之间可能存在自然的竞争条件,例如,一条消息可能在写入套接字后但在到达消费者之前过期。
当设置按消息 TTL 时,过期消息可能会排在未过期消息后面,直到后者被消费或过期。因此,这些过期消息占用的资源将不会被释放,并且它们将被计入队列统计信息(例如,队列中的消息数量)。
在追溯应用按消息 TTL 策略时,建议让消费者在线,以确保消息更快地被丢弃。
鉴于现有队列上按消息 TTL 设置的这种行为,当需要删除消息以释放资源时,应改用队列 TTL(或队列清除,或队列删除)。
队列 TTL
TTL 也可以设置在队列本身上,而不仅仅是队列的内容。此功能可以与 自动删除队列属性 一起使用。
通常,仅为临时(非持久性)的经典队列设置队列 TTL(过期)才有意义。Streams 不支持过期。
当队列未使用时,队列才会在一段时间后过期(如果队列有在线消费者,则认为队列被使用)。
可以通过在 queue.declare 中设置 x-expires 参数,或者设置 expires 策略来为给定队列设置过期时间。这控制了队列在未使用多长时间后会被自动删除。未使用是指队列没有消费者,队列没有最近被重新声明(重新声明会续订租约),并且在至少一个过期期间内没有调用 basic.get。例如,这可用于 RPC 样式的应答队列,其中可以创建许多可能永远不会被消耗的队列。
服务器保证,如果队列在至少一个过期期间内未被使用,则会将其删除。但服务器不对过期时间过多久才删除队列做出保证。
x-expires 参数或 expires 策略的值以毫秒为单位描述了过期周期。它必须是一个正整数(与消息 TTL 不同,它不能为 0)。因此,值为 1000 意味着一个队列在未使用 1 秒后将被删除。
使用策略定义队列的队列 TTL
以下策略使所有队列在最后一次使用后 30 分钟过期。
- 使用 rabbitmqctl (bash)
- 使用 rabbitmqadmin (bash)
- 使用 rabbitmqctl (PowerShell)
- 使用 rabbitmqadmin (PowerShell)
rabbitmqctl set_policy expiry ".*" '{"expires":1800000}' --apply-to queues
rabbitmqadmin policies declare \
--name "expiry" \
--pattern ".*" \
--definition '{"expires":1800000}' \
--apply-to "queues"
rabbitmqctl.bat set_policy expiry ".*" "{""expires"":1800000}" --apply-to queues
rabbitmqadmin.exe policies declare ^
--name "expiry" ^
--pattern ".*" ^
--definition "{""expires"":1800000}" ^
--apply-to "queues"
使用 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);