RabbitMQ 消息过期 TTL
TTL(Time To Live,生存时间)让消息在队列里存活指定时长后自动过期,是构建"临时凭证、定时失效"类业务的基础能力。RabbitMQ 的过期分消息级与队列级两种,单位都是毫秒。
消息级 TTL
发布时给单条消息设置 expiration 属性,只对这条消息生效,过期从消息进入队列那一刻起算:
import pika
ch = pika.BlockingConnection(pika.ConnectionParameters("127.0.0.1")).channel()
props = pika.BasicProperties(expiration="60000") # 60 秒后过期
ch.basic_publish(exchange="", routing_key="q.verify",
body=b"code:889966", properties=props)
每条消息可设不同 TTL,适合同一队列中存活时长各不相同的消息。
队列级 TTL(x-message-ttl)
声明队列时指定 x-message-ttl,则该队列中所有消息统一按此时长过期;该参数在队列有消息后无法修改,只能删队列重建:
# 声明队列:队列内所有消息 60 秒过期
rabbitmqadmin declare queue name=q.ttl60 arguments='{"x-message-ttl":60000}'
消息级与队列级 TTL 都设置时,取两者中的较小值。
| 设置方式 | 位置 | 作用对象 | 改动成本 |
|---|---|---|---|
| expiration 属性 | 消息属性 | 单条消息 | 每条可不同,无需重建 |
| x-message-ttl | 队列参数 | 队列内全部消息 | 需删队列重建 |
队列自身过期(x-expires)
x-expires 不是消息过期,而是"队列空闲自动删除":队列持续指定毫秒没有被使用(无消费者、无 basic.get 取消息、无新消息入队等)就整队列删除,其中的消息随之丢失。典型用于临时队列自清理,避免长期残留:
# 队列 5 分钟无人使用即自动删除
rabbitmqadmin declare queue name=q.tmp arguments='{"x-expires":300000}'
过期机制与坑
RabbitMQ 只在队头检查过期:消息到达队头时才被判定过期并清除,队头之后的消息即使已过期也仍占着队列,等轮到它才被清理。
由此带来最常见的坑:先入队的长 TTL 消息堵在队头,会让排在后面本应更早过期的短 TTL 消息迟迟不过期。例如先发一条 10 分钟过期的消息,再连发 1 分钟过期的消息,后者要等队头清空后才开始被清理,实际失效时间远晚于预期。
另外,已过期但未轮到清理的消息仍会计入队列长度与 ready 数,监控里看到队列"有消息"可能是已过期的残影。
这条特性决定了消息级 TTL 的过期并不精确,对过期精度敏感的业务应考虑死信/延迟队列方案或应用侧自行计时。
典型场景:验证码过期
登录/注册验证码常用"5 分钟有效":发送时把验证码消息设好 TTL,即使消费者延迟处理,队列里的旧验证码也会因过期自动清除,避免把过期验证码继续投给用户。
类似场景还有短期 token、限时优惠券、临时通知的自动失效。
小结
TTL 单位毫秒:单条消息用 expiration 属性、整队列用 x-message-ttl、队列空闲自清理用 x-expires。记住"只在队头检查过期"的机制,设计时避免长 TTL 阻塞短 TTL,过期类业务即可放心使用。