# 过期时间 TTL
Time to Live 简称 TTL,即过期时间。RabbitMQ 可以对 消息 和 队列 设置 TTL。
# 设置消息的 TTL
- 通过队列设置:队列中的消息都有相同的过期时间
- 对消息本身设置:每条消息的 TTL 可以不同
如果两种一起设置,则以最小的 TTL 生效。
消息在队列中生存时间一旦超过 TTL,就会变成「死信(Dead Message)」,消费者将无法收到该消息。(具体细节后续章节讲解)
# 在队列上设置
定义队列时,通过参数 x-message-ttl
设置,单位是 毫秒
final HashMap<String, Object> arguments = new HashMap<>();
arguments.put("x-message-ttl", 6000);
channel.queueDeclare(QUEUE_NAME, true, false, false, arguments);
1
2
3
2
3
TTL 值得几种情况:
- 值为 0 :表示,除非此时可以直接将消息投递到消费者,否则该消息被立即丢弃
- 大于 0:将在该时间内过期,
# 在消息设置
通过 BasicProperties 来设置 expiration 属性:
final AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties().builder();
builder.deliveryMode(2); // 持久化消息
builder.expiration("60000"); //设置消息的 ttl
channel.basicPublish(EXCHANGE_NAME,
"",
true,
builder.build(),
"mandatory test".getBytes()
);
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
此种方式当超过 TTL 时,并不会立即从队列中抹去,而是在投递消费者时判定的。而在队列上一旦过期,则立即从队列中抹去。
这是因为内部实现的原因导致的:
- 队列中已过期的消息肯定在队列头部,只要定期从队头开始扫描是否有过期的消息即可
- 在消息中设置的过期,需要扫描整个队列。
其实这个地方,笔者并不能明白书上锁讲的,为什么要扫描整个队列?队列过期为什么就会在头部?
# 设置队列的 TTL
定义队列时间,通过参数 x-expires
参数,单位为毫秒
final HashMap<String, Object> arguments = new HashMap<>();
// 该参数必须大于 0,要么就不设置
arguments.put("x-expires", 6000);
channel.queueDeclare(QUEUE_NAME, true, false, false, arguments);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY);
1
2
3
4
5
2
3
4
5
队列的 TTL 其实就是在声明:当队列空闲多久时,被自动删除。
**空闲多久指的是:**队列上没有任何消费者、也没有被重新声明、并且在过期时间内也未调用过 Basic.Get 命令
适合使用的场景:可以应用在类似 RPC 方式的回复队列,在 RPC 中,许多队列会被创建出来,但是未被使用。(这里笔者也不知道什么是 RPC 回复队列)