本文转载自RabbitMQ之TTL(Time-To-Live 过期时间)

概述

RabbitMQ可以对消息和队列设置TTL. 目前有两种方法可以设置。第一种方法是通过队列属性设置,队列中所有消息都有相同的过期时间。第二种方法是对消息进行单独设置,每条消息TTL可以不同。如果上述两种方法同时使用,则消息的过期时间以两者之间TTL较小的那个数值为准。消息在队列的生存时间一旦超过设置的TTL值,就称为dead message, 消费者将无法再收到该消息。


设置队列属性

通过队列属性设置消息TTL的方法是在queue.declare方法中加入x-message-ttl参数,单位为ms.

例如:

package com.vms.test.zzh.rabbitmq.self;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.apache.commons.collections.map.HashedMap; import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException; /
* Created by hidden on 2017/2/7.
*/
public class RBttlTest {
public static final String ip = "xx.xx.xx.73";
public static final int port = 5672;
public static final String username = "root";
public static final String password = "root"; public static final String queueName = "queue.ttl.test";
public static final String exchangeName = "exchange.ttl.test";
public static final String routingKey = "ttl";
public static final Boolean durable = true;
public static final Boolean exclusive = false;
public static final Boolean autoDelete = false; public static void main(String[] args) {
try {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(ip);
factory.setPort(port);
factory.setUsername(username);
factory.setPassword(password); Connection connection = factory.newConnection();
Channel channel = connection.createChannel(); Map<String, Object> argss = new HashMap<String, Object>();
argss.put("vhost", "/");
argss.put("username","root");
argss.put("password", "root");
argss.put("x-message-ttl",6000);
channel.queueDeclare(queueName, durable, exclusive, autoDelete, argss);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}

通过RabbitMQ的管理页面可以看到有新的queue生成,并标记为TTL(上面的代码同时会将此queue设置为durable=true,以及包含相关参数,比如vhost=/),如下图所示:

另外也可以同rabbitmq的命令行模式来设置:

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

还可以通过HTTP接口调用:

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

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


设置消息属性

针对每条消息设置TTL的方法是在basic.publish方法中加入expiration的属性参数,单位为ms.

关键代码:

AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();
builder.deliveryMode(2);
builder.expiration("6000");
AMQP.BasicProperties properties = builder.build(); channel.basicPublish(exchangeName,routingKey,mandatory,properties,"ttlTestMessage".getBytes());

也可以写成:

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

具体代码如下所示:

public static void main(String[] args) throws InterruptedException {
sendTTLMessage();
TimeUnit.SECONDS.sleep(5);
consumeTTLMessage();
} public static void sendTTLMessage(){
try {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(ip);
factory.setPort(port);
factory.setUsername(username);
factory.setPassword(password); Connection connection = factory.newConnection();
Channel channel = connection.createChannel(); AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();
builder.deliveryMode(2);
builder.expiration("6000");
AMQP.BasicProperties properties = builder.build(); channel.basicPublish(exchangeName,routingKey,mandatory,properties,"ttlTestMessage".getBytes()); channel.close();
connection.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
} public static void consumeTTLMessage(){
try {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(ip);
factory.setPort(port);
factory.setUsername(username);
factory.setPassword(password); Connection connection = factory.newConnection();
Channel channel = connection.createChannel(); QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(queueName, true, consumer);
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
System.out.println(" [X] Received '" + message + "'"); channel.close();
connection.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

当TimeUnit.SECONDS.sleep(5);设置为5s时可以消费到消息,当设置为7s时,则消费不到消息,因为此时已经超时了。

还可以通过HTTP接口调用如下:

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

对比

对于第一种设置队列TTL属性的方法,一旦消息过期,就会从队列中抹去,而第二种方法里,即使消息过期,也不会马上从队列中抹去,因为每条消息是否过期时在即将投递到消费者之前判定的,为什么两者得处理方法不一致?因为第一种方法里,队列中已过期的消息肯定在队列头部,RabbitMQ只要定期从队头开始扫描是否有过期消息即可,而第二种方法里,每条消息的过期时间不同,如果要删除所有过期消息,势必要扫描整个队列,所以不如等到此消息即将被消费时再判定是否过期,如果过期,再进行删除。


Queue TTL

queue.declare 命令中的 x-expires 参数控制 queue 被自动删除前可以处于未使用状态的时间。未使用的意思是 queue 上没有任何 consumer ,queue 没有被重新声明,并且在过期时间段内未调用过 basic.get 命令。该方式可用于,例如,RPC-style 的回复 queue, 其中许多 queue 会被创建出来,但是却从未被使用。

服务器会确保在过期时间到达后 queue 被删除,但是不保证删除的动作有多么的及时。在服务器重启后,持久化的 queue 的超时时间将重新计算。

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

下面的 Java 示例创建了一个 queue ,其会在 30 分钟不使用的情况下判定为超时。

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

参考资料

  1. Time-To-Live Extensions
  2. RabbitMQ 之 TTL 详解(翻译)
  3. RabbitMQ(三)RabbitMQ消息过期时间(TTL)

RabbitMQ之TTL(Time-To-Live 过期时间)的更多相关文章

  1. redis 过期时间与缓存

    设置过期时间 redis对于存储的键值可以设置过期时间,对于过期了的键值,redis会自动删除. > OK > get price " > expire price (in ...

  2. RabbitMQ 设置消息的TTL(过期时间)

    我们在RabbitMQ中发布消息时,在代码中有两种方法设置某个队列的消息过期时间: 1.针对队列来说,可以使用x-message-ttl参数设置当前队列中所有消息的过期时间,即当前队列中所有的消息过期 ...

  3. RabbitMQ(三)RabbitMQ消息过期时间(TTL)

    在RabbitMQ(二)AMQP协议mandatory和immediate标志位区别中我们提到,在RabbitMQ3.0以后的版本里,去掉了immediate参数支持,要实现类似的确认功能要使用TTL ...

  4. 【RabbitMQ 实战指南】一 过期时间TTL

    RabbitMQ 可以对消息和队列设置过期时间(TTL) 1.设置消息的TTL 目前有两种方式可以设置消息的TTL 第一种方式是通过队列属性设置,队列中所有消息都有相同的过期时间 第二种方式是对消息本 ...

  5. RabbitMQ 设置队列的过期时间

    设置队列的过期时间非常简单,在声明队列时,设置x-expires参数即可.当队列的生存周期超时后,RabbitMQ server会自动将该队列删除. 代码如下: channel.QueueDeclar ...

  6. rabbitMq 学习笔记(二) 备份交换器,过期时间,死信队列,死信队列

    备份交换器 备份交换器,英文名称为 Altemate Exchange,简称庙,或者更直白地称之为"备胎交换器". 生产者在发送消息的时候如果不设置 mandatory 参数, 那 ...

  7. 面试官:RabbitMQ过期时间设置、死信队列、延时队列怎么设计?

    哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 RabbitMQ我们经常的使用, ...

  8. RabbitMQ与.net core(三) fanout类型Exchange 与 消息的过期时间 与 队列的存活时间

    上一篇我们讲了关于direct类型的Exchange,这一片我们来了解一下fanout类型的Exchange. 1.Exchange的fanout类型 fanout类型的Exchange的特点是会把消 ...

  9. redis中获取没有设置ttl过期时间的key

    需求:redis作为一个内存型的数据库,我们需要对过期key保持关注,从info keyspace中可以看出有多少key没有设置过期时间,那么到底是哪些呢? 说明:关于redis ttl 的返回值,请 ...

随机推荐

  1. Weblogic漏洞利用

    Weblogic漏洞 Weblogic任意文件上传(CVE-2018-2894) 受影响版本 weblogic 10.3.6.0.weblogic 12.1.3.0.weblogic 12.2.1.2 ...

  2. Go语言学习笔记(2)——零散的话题(反射)

    这部分是<Go语言编程>这本书的第9章的内容.书中给该章节的定位是一个文章集,其包含了一些Go语言中比较少涉及,或是比较深入的讨论的内容.因为第一节就是反射,而反射在我看来是比较重要的内容 ...

  3. Qt项目的发布

    Qt项目的发布 (1)首先将项目调为发布版 (2)找到缺失的DLL文件 发布好了后,双击生成的exe文件可能会出现如下的问题 像这样的错误警告可能会弹出好几个,对于这种错误有2种解决方案. 第一种:配 ...

  4. Java程序操作HBase

    package com.zy.test; import java.io.IOException; import org.apache.hadoop.conf.Configuration; import ...

  5. FunnyXEN

    For any positive integer n, we define function F(n) and XEN(n).For a collection S(n)={1,2,...,2n}, w ...

  6. E 快速排序

    :以下代码可以从数组a[]中找出第k小的元素. 它使用了类似快速排序中的分治算法,期望时间复杂度是O(N)的. 请仔细阅读分析源码,填写划线部分缺失的内容. #include <stdio.h& ...

  7. The 2019 Asia Nanchang First Round Online Programming Contest C. Hello 2019(动态dp)

    题意:要找到一个字符串里面存在子序列9102 而不存在8102 输出最小修改次数 思路:对于单次询问 我们可以直接区间dpOn求出最小修改次数 但是对于多次询问 我在大部分题解看到的解释一般是用线段树 ...

  8. Little Difference Gym - 101612L 思维

    题意: 给你一个数n,你需要输出它可以由那几个数相乘构成,我们设可以由x个数构成,这x个数中最小值为minn,最大值为maxx,那么要求maxx-minn<=1 问你满足上面要求的情况有多少种. ...

  9. Codeforces Round #653 (Div. 3) A. Required Remainder (数学)

    题意:有三个正整数\(x,y,n\),再\(1\)~\(n\)中找一个最大的数\(k\),使得\(k\ mod\ x=y\). 题解:先记\(tmp=n/x\),再判断\(tmp*x+y\)的值是否大 ...

  10. 六、Python集合定义和基本操作方法

    一.集合的定义方法及特点 1.特点: (1)由不同元素组成 #集合由不同元素构成 s={1,2,3,3,4,3,3,} print(s)#运行结果:{1, 2, 3, 4} (2)集合无序 #集合无序 ...