生存时间 (Time-to-Live) 和过期
本文档指南涵盖的关键主题包括:
- RabbitMQ 支持的队列 TTL 和消息 TTL 功能概述
- 基于队列的 在队列级别定义的消息 TTL
- 基于消息的 由发布者定义的 TTL
- 消息 TTL 与死信
- 追溯应用的消息 TTL
- 队列 TTL(队列的过期)
生存时间功能
在 RabbitMQ 中,您可以为消息和队列设置 TTL(生存时间)参数或策略。顾名思义,TTL 指定了消息和队列“存活”的时间段。
消息 TTL 决定了消息在队列中可以保留多久。如果消息在队列中的保留时间超过了队列的消息 TTL,则消息过期并被丢弃。
“丢弃”意味着消息不会被投递给任何已订阅的消费者,也无法通过直接在队列上使用 basic.get 方法获取。消息 TTL 可以应用于单个队列、一组队列,或者基于每条消息进行应用。
TTL 也可以设置在队列上,而不仅仅是队列内容。此功能可以与自动删除队列属性配合使用。通常,仅对瞬态(非持久化)的经典队列设置 TTL(过期时间)才有意义。流 (Streams) 不支持过期。
队列仅在未被使用时才会经过一段时间后过期(如果队列有在线消费者,则视为正在使用)。
TTL 行为由 可选队列参数 控制,配置它的最佳方式是使用 策略 (policy)。
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"
这将对所有队列应用 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 会导致消息在到达队列后立即过期,除非它们能立即被投递给消费者。因此,这提供了一种替代 RabbitMQ 服务器不支持的 immediate 发布标志的方法。与该标志不同的是,系统不会发出 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 queues) 在过期消息到达队列头部时将其设为死信。
经典队列
经典队列在以下几种情况下会将过期消息设为死信:
- 当消息到达队列头部时
- 当队列收到影响其的策略变更通知时
追溯应用每消息 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);