TTL概念
TTL是time to live的缩写,生存时间
消费者队列中设置TTL
RabbitMQ支持消息的过期时间,消息发送时可以指定,从消息入队列开始计算,只要超过队列的超时时间配置,消息就会自动清除
消费端代码
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-message-ttl", 60000);
channel.queueDeclare("myqueue", false, false, false, args);
public class Consumer {
public static void main(String[] args) throws Exception {
//1 创建一个ConnectionFactory, 并进行配置
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.17.17");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
//2 通过连接工厂创建连接
Connection connection = connectionFactory.newConnection();
//3 通过connection创建一个Channel
Channel channel = connection.createChannel();
//4 声明(创建)一个队列
String queueName = "testttl";
//队列中设置ttl,如果20秒内不消费,将自动删除该消息
Map<String, Object> argttl = new HashMap<String, Object>();
argttl.put("x-message-ttl", 20000);
channel.queueDeclare(queueName, true, false, false, argttl);
//5 创建消费者
QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
//6 设置Channel
//1、消费的队列2、是否自动签收,当消费者接受后,消费端给broker回送一条ack的消息,告诉收到,
//如果false,需要代码上指定,一般是false,处理完消息后,手工返回 3、消费者对象
channel.basicConsume(queueName, true, queueingConsumer);
while(true){
//7 获取消息
Delivery delivery = queueingConsumer.nextDelivery();
String msg = new String(delivery.getBody());
System.err.println("消费端: " + msg);
//Envelope envelope = delivery.getEnvelope(); //可以获得消息的队列和exchange
}
}
}
生产者每条消息设置TTL
TTL 设置可以具体到每一条 message 本身,只要在通过 basic.publish 命令发送 message 时设置 expiration 字段
生产者代码
示例 publish 了最多能在 queue 中存活 60 秒的 message :
byte[] messageBodyBytes = "Hello, world!".getBytes();
AMQP.BasicProperties properties = new AMQP.BasicProperties();
properties.setExpiration("60000");
channel.basicPublish("myexchange", "routingkey", properties, messageBodyBytes);
public class Procuder {
public static void main(String[] args) throws Exception {
//1 创建一个ConnectionFactory, 并进行配置
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.17.17");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
//2 通过连接工厂创建连接
Connection connection = connectionFactory.newConnection();
//3 通过connection创建一个Channel
Channel channel = connection.createChannel();
//4 通过Channel发送数据
for(int i=0; i < 5; i++){
String msg = "Hello RabbitMQ!";
//1 exchange 2 routingKey 3 BasicProperties(修饰消息的附加属性) 4、body(消息的实体)
//如果exchange为空,使用默认的路由,此时routingkey和queue是一样的名称,如果有一样的名称才能发送成功
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
.deliveryMode(2)
.contentEncoding("UTF-8")
.expiration("20000")
.build();
channel.basicPublish("", "testttl", properties, msg.getBytes());
}
//5 记得要关闭相关的连接
channel.close();
connection.close();
System.out.println("success");
}
}
当同时指定了 queue 和 message 的 TTL 值,则两者中较小的那个才会起作用。
死信队列
当消息在一个队列中变成死信(消息没有任何消费者去消费)之后,它能被重新publish到另一个Exchange,这个Exchange就是DLX
DLX也是一个正常的Exchange,和一般的Exchange没什么区别,它能在任何的队列上被指定,实际就是设置某个队列的属性
当这个队列中有死信时,RabbitMQ就会自动将这个消息重新发布到设置的Exchange上去,进而路由到另一个队列
消息变为死信的几种情况
消息被拒绝(basic.rejec/basic.nack)且requeue=false
channel.basicNack(envelope.getDeliveryTag(), false, false)
TTL过期
队列超时设置或消息的超时设置
队列达到最长长度
死信队列的设置
设置死信队列的exchange和queue,然后进行绑定
Exchange:dlx.exchange
Queue:dxs.queue
RoutingKey:#
正常声明交换机、队列、绑定,只不过我们需要在队列加上一个参数:arguments.put(“x-dead-letter-exchange”,” dlx.exchange”);
生产端代码
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
.deliveryMode(2)
.contentEncoding("UTF-8")
.expiration("10000")
.build();
channel.basicPublish(exchange, routingKey, properties, msg.getBytes());
public class Producer {
public static void main(String[] args) throws Exception {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.17.17");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
String exchange = "test_dlx_exchange";
String routingKey = "dlx.save";
String msg = "Hello RabbitMQ DLX Message";
for(int i =0; i<1; i ++){
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
.deliveryMode(2)
.contentEncoding("UTF-8")
.expiration("10000")
.build();
channel.basicPublish(exchange, routingKey, properties, msg.getBytes());
}
}
}
消费端代码
channel.exchangeDeclare(exchangeName, "topic", true, false, null);
Map<String, Object> agruments = new HashMap<String, Object>();
agruments.put("x-dead-letter-exchange", "dlx.exchange");
//这个agruments属性,要设置到声明队列上
channel.queueDeclare(queueName, true, false, false, agruments);
channel.queueBind(queueName, exchangeName, routingKey);
//要进行死信队列的声明:
channel.exchangeDeclare("dlx.exchange", "topic", true, false, null);
channel.queueDeclare("dlx.queue", true, false, false, null);
channel.queueBind("dlx.queue", "dlx.exchange", "#");
//#
channel.basicConsume(queueName, true, new MyConsumer(channel));
public class Consumer {
public static void main(String[] args) throws Exception {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.17.17");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 这就是一个普通的交换机 和 队列 以及路由
String exchangeName = "test_dlx_exchange";
String routingKey = "dlx.#";
String queueName = "test_dlx_queue";
channel.exchangeDeclare(exchangeName, "topic", true, false, null);
Map<String, Object> agruments = new HashMap<String, Object>();
agruments.put("x-dead-letter-exchange", "dlx.exchange");
//这个agruments属性,要设置到声明队列上
channel.queueDeclare(queueName, true, false, false, agruments);
channel.queueBind(queueName, exchangeName, routingKey);
//要进行死信队列的声明:
channel.exchangeDeclare("dlx.exchange", "topic", true, false, null);
channel.queueDeclare("dlx.queue", true, false, false, null);
channel.queueBind("dlx.queue", "dlx.exchange", "#");
//#
channel.basicConsume(queueName, true, new MyConsumer(channel));
}
}