bigywater.tech
RabbitMQ · 33

TTL:消息 TTL 与队列 TTL 的过期时机

TTL 看起来简单——到时间就删。但过期是在什么时刻真正发生的?队列 TTL 和消息 TTL 谁说了算?expiration=0 是什么意思?队列自己的 TTL 又怎么算?这篇一项项在 RabbitMQ 4.3.6 上量。

11 条
队头没过期时,后面 10 条已过期的消息仍留在队列里的总数
≈ 3 s
x-expires=3000 的队列在无人使用后被删除的时间,passive 声明也会重置计时
0 条
停机 8 秒、TTL 8000 ms 的持久化消息在重启后剩下的条数

消息过期

实测 · 本机执行输出
  (秒, ready): [(0.0, 10), (0.62, 10), (1.26, 0), (1.91, 0)]

消息 TTL 到点后从队列里移除(走死信或丢弃),消费者不会收到;实测 1000 ms 约 1 秒时整批过期。

只看队头

实测 · 本机执行输出
  3 秒后 ready = 11(11 条:队头没有过期,后面已经过期的 10 条不会被清掉)
  basic_get 取空,实际拿到: ['head-no-ttl'](已过期的 10 条在到达队头时被丢掉,消费者看不到)

过期检查只在队头进行:队头没过期时,后面过期的消息继续占用队列,到达队头时才被丢弃,消费者看不到它们。

两种 TTL

实测 · 本机执行输出
  exp500(队列 TTL 2000):[(0.0, 1), (0.9, 0), (1.8, 0), (2.7, 0)]
  exp5000(队列 TTL 2000):[(0.0, 1), (0.9, 1), (1.8, 0), (2.7, 0)]——较小的 2000 ms 生效

队列的 x-message-ttl 与消息的 expiration 同时存在时取较小的。

expiration=0

实测 · 本机执行输出
  无消费者 + expiration=0:队列里 ready = 0
  有一个空闲消费者 + expiration=0:消费者收到 ['with-consumer']

expiration=0 表示只在能立即投递给消费者时保留,否则立刻丢弃。

队列 TTL

实测 · 本机执行输出
  声明后什么都不做,用 rabbitmqctl list_queues(不算“使用”)每 0.5 s 看一次: [(0.0, True), (0.9, True), (1.9, True), (2.8, False), (3.7, False), (4.7, False)]
  每秒做一次 passive 声明: [(1, True), (2, True), (3, True), (4, True), (5, True), (6, True)]——passive 声明也重置了计时,队列一直在
  有一个消费者连着时,5 秒后队列还在: True
  消费者断开后,每 0.5 s 看一次: [(0.0, True), (0.9, True), (1.8, True), (2.8, False), (3.7, False), (4.6, False)]

x-expires 是队列无人使用多久后被删除。消费者连着、basic_get、重新声明(包括 passive)都算使用。

重启

实测 · 本机执行输出
  重启后队列 t6 的 ready = 0

过期时间从发布时刻起算,broker 停机期间也在走,重启后已过期的消息不再出现。

分步演示

TTL
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / RabbitMQ 4.3.6 / Erlang/OTP 28.5 / pika 1.4.4(Homebrew 与临时虚拟环境);所有节点都是本机自己起的 RabbitMQ 进程(127.0.0.1,端口 9500 以上,每个实验独立的数据目录与节点名,不连任何外部服务);命令输出来自真实的 rabbitmqctl 与管理 API,发布与消费用 pika 的真实连接;计时用 time.perf_counter,数字每次运行会有小幅抖动。读队列条数用 rabbitmqctl list_queues(每次读本身要几百毫秒,时间戳是读之前的);x-expires 的存在检查用 list_queues name(只读元数据,不碰队列进程);第六节关闭 broker 用 rabbitmqctl shutdown
    • 没有验证:quorum 队列和 stream 队列上同样的 TTL 行为(第 11 篇看过 quorum 的队头阻塞);大量 TTL 消息的 CPU 开销;集群里队列 TTL 的清理;TTL 与死信的组合(见第 10、11 篇);expiration 字符串不合法时的错误
    京ICP备2026067502号-1京公网安备11010502063487号