所有分类
  • 所有分类
  • 未分类

RabbitMQ消息的过期时间(TTL)-使用/原理

简介

本文介绍RabbitMQ的消息的过期时间。

本内容也是Java后端面试常见的问题。

TTL,Time to live的简称,即过期时间。RabbitMQ可以对消息和队列设置TTL。

消息的过期时间

如果不设置TTL,则表示此消息不会过期;如果将TTL设置为0,则表示除非此时可以直接将消息投递到消费者,否则该消息会被立即丢弃,这个特性可以部分替代RabbitMQ3.0版本
之前的immediate参数,之所以部分代替,是因为immediate参数在投递失败时会用Basic.Return将消息返回(这个功能可以用死信队列来实现)。

目前有两种方法可以设置消息的TTL:

  • 法1:通过队列属性设置:
    • 这样队列中所有消息都有相同的过期时间。
  • 法2:对消息本身进行单独设置
    • 每条消息的TTL可以不同。

如果两种方法一起使用,则消息的TTL以两者之间较小的那个数值为准。消息在队列中的生存时间一旦超过设置的TTL值时,就会变成“死信”(DeadMessage),消费者将无法再收到该消息。(这点不是绝对的,详见:死信队列)。

通过队列属性设置

通过队列属性设置消息TTL的方法是在channel.queueDeclare方法中加入x-message-ttl参数实现的,这个参数的单位是毫秒。

设置方法有如下几种:

1. 通过代码设置

Map<String, Object> args = new HashMap<String, Object> ();
args.put("x-message-ttl",6000);
channel.queueDeclare(queueName, durable, exclusive, autoDelete, args);

 2.通过命令设置

rabbitmqctl set_policy TTL ".*" 1{"message-ttl":60000}' --apply-to queues

3.通过HTTP API设置

curl -i -u root:root -H "content-type:application/json"-X POT
-d'{"auto_delete":false,"durable":true,"arguments":{"x-message-ttl": 60000}}'
http://localhost:15672/api/queues/{vhost}/{queuename}

直接设置消息的TTL

对每条消息设置TTL的方法是在channel.basicPublish方法中加入expiration的属性参数,单位为毫秒。

法1:通过代码设置

 写法1:

AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();
builder.deliveryMode(2);		//持久化消息
builder.expiration("60000") ;//设置 TTL=60000ms
AMQP.BasicProperties properties = builder.build();
channel.basicPublish(exchangeName,routingKey,mandatory,properties,
	"ttlTestMessage".getBytes());

写法2:

AMQP.BasicProperties properties = new AMQP.BasicProperties();
properties.setDeliveryMode(2);
properties.setExpiration("60000");
channel.basicPublish(exchangeName,routingKey,mandatory,properties,
	"ttlTestMessage".getBytes();

法2:通过HTTP API接口设置

curl -i -u root:root -H "content-type:application/json" -X POST -d
'{"properties":{"expiration":"60000"},"routing_key":"routingkey",
"payload": "my body",
"payload_encoding": "string" }'
http://localhost:15672/api/exchanges/{vhost}/{exchangename}/publish

对于第一种设置队列TTL属性的方法,一旦消息过期,就会从队列中抹去,而在第二种方法(设置消息的TTL)中,即使消息过期,也不会马上从队列中抹去,因为每条消息是否过期是在即将投递到消费者之前判定的。

为什么这两种方法处理的方式不一样?因为第一种方法里,队列中己过期的消息肯定在队列头部,RabbitMQ只要定期从队头开始扫描是否有过期的消息即可。而第二种方法里,每条消息的过期时间不同,如果要删除所有过期消息势必要扫描整个队列,所以不如等到此消息即将被消费时再判定是否过期,如果过期再进行删除即可。 

队列的过期时间

通过channel.queueDeclare方法中的x-expires参数可以控制队列被自动删除前处于未使用状态的时间。未使用的意思是队列上没有任何的消费者,队列也没有被重新声明,并且在过期时间段内也未调用过Basic.Get命令。

设置队列里的TTL可以应用于类似RPC方式的回复队列,在RPC中,许多队列会被创建出来,但是却是未被使用的。

RabbitMQ会确保在过期时间到达后将队列删除,但是不保障删除的动作有多及时。在RabbitMQ重启后,持久化的队列的过期时间会被重新计算。

用于表示过期时间的x-expires参数以毫秒为单位,并且服从和x-message-ttl—样的约束条件,不过不能设置为0。比如该参数设置为1000,则表示该队列如果在1秒钟之内未使用则会被删除。

代码示例:创建一个过期时间为30分钟的队列

Map<String, Object> args = new HashMap<String, Object>{);
args.put("x-expires", 1800000);
channel.queueDeclare("myqueue", false, false, false, args);
1

评论3

请先

  1. 提个建议,代码框下方的左右滑动条不太好点击,可以调大一点,或者换个好看的样式
    秋风扫落叶 2023-09-18 0
    • 好的,我改大一些
      自学精灵 2023-09-18 0
    • 已调大,请刷新页面。
      自学精灵 2023-09-18 2
显示验证码
没有账号?注册  忘记密码?

社交账号快速登录