一、 什么是TTL(Time To Live)
TTL是RabbitMQ中消息或者队列的属性,注意是消息或者队列。表明一条消息或者该队列中的所有消息的最大存活时间,单位是:毫秒。
简单讲就是:设置了TTL的消息,在设置的时间内没有被消费的话,就会被认为是过期的,那么这条消息会被转到死信队列或者是丢弃。比如设置一条消息的TTL是5分钟,那么在5分钟内这条消息没有被消费掉,那么就属于过期的消息了,进而被死信或者丢弃
二、消息设置TTL
消息设置TTL需要在发布消息的时候,为消息属性头中添加属性,我们使用AMQP.BasicProperties这个属性封装类来设置
// 创建一个交换机,不创建也可以,直接使用默认的
channel.exchangeDeclare("direct1",BuiltinExchangeType.DIRECT);
// 创建队列
channel.queueDeclare(QUEUE_NAME, false, false, true, null);
// 绑定队列和交换机
channel.queueBind(QUEUE_NAME,"direct1",QUEUE_NAME);
// 设置消息属性BasicProperties中的expiration
AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();
builder.expiration("10000");
for (int i = 0; i < 10; i++) {
channel.basicPublish("direct1", QUEUE_NAME, builder.build(), (msg + i).getBytes());
}
BasicProperties中的expiration就是设置消息的超时时间,单位是毫秒
运行代码并观察RabbitMQ后台
查看消息属性,已经存在TTL了,十秒后观察队列如下,队列中的消息已被删除
不过这里个人是有疑问的,对于消息本身设置TTL的方式,翻阅其他资料时都有些到一个点,在仅设置了消息TTL的情况下,消息过期后并不会立刻被删除,而是等到被消费的时候才会判断该消息是否过期。但是我实际测试的结果发现,消息还是在到期之后立刻被删除了。不知道是有其他机制在干预还是什么,后续会在深入看一下。
三、 队列属性设置TTL
队列属性设置TTL和队列TTL是两个东西,通过属性设置的是队列中所有消息,而队列TTL是设置队列自身的TTL,因为队列自身也可以有过期时间,这两个概念要区分一下
// 创建一个交换机,不创建也可以,直接使用默认的
channel.exchangeDeclare("direct1", BuiltinExchangeType.DIRECT);
// 创建队列并且声明属性x-message-ttl
Map<String, Object> arguments = new HashMap<>();
arguments.put("x-message-ttl", 10000);
channel.queueDeclare(QUEUE_NAME, true, false, true, arguments);
// 绑定交换机与队列
channel.queueBind(QUEUE_NAME, "direct1", QUEUE_NAME);
for (int i = 0; i < 10; i++) {
channel.basicPublish("direct1", QUEUE_NAME, null, (msg + i).getBytes());
}
创建队列后,我在RabbitMQ后台查看队列的属性
从后台可以看到队列已经具备x-message-ttl属性了,这个属性对以后进入该队列的消息都会生效。但是我们再查看消息的属性的时候,消息本身就没有expiration这个属性了。
- 问题思考: 如果以上两种都设置了,哪个会生效?
答:会以TTL中值较小的为准
四、队列TTL
上面的两种设置TTL所针对的目标都是消息本身,那队列TTL的目标就是设置队列自身的TTL,队列过期后队列自身会被RabbitMQ服务器删除
channel.exchangeDeclare("direct1", BuiltinExchangeType.DIRECT);
// 创建队列的时候,使用x-expires属性
Map<String,Object> arguments = new HashMap<>();
arguments.put("x-expires",10000);
channel.queueDeclare(QUEUE_NAME, true, false, true, arguments);
channel.queueBind(QUEUE_NAME, "direct1", QUEUE_NAME);
for (int i = 0; i < 10; i++) {
channel.basicPublish("direct1", QUEUE_NAME, null, (msg + i).getBytes());
}
在创建队列的时候,我们使用x-expires属性,就可以设置队列自身的TTL了
通过后台观察队列的属性,发现存在x-expires :10000的属性,说明设置成功,10秒后控制台如下,该队列被删除
4.1 特殊性
- 设置了TTL的队列并不是在到时间后马上就删除,被设置了x-expires属性的队列要想被删除,必须处于未使用的状态,也就是说这个队列上没有任何消费者在消费或者等待消费,队列也没有被重新声明,并且在过期时间段内也未调用过Basic.Get 命令。如果该队列设置了持久化,在重启后,这个时间会重新计算。