RabbitMQ消费端ACK与重回队列机制,TTL,死信队列详解(十一)
消费端的手工ACK和NACK
消费端进行消费的时候,如果由于业务异常我们可以进行日志的记录,然后进行补偿。
如果由于服务器宕机等严重问题,那么我们就需要手工进行ACK保障消费端成功。
消费端重回队列
为了对没有处理成功的消息,把消息重新回递给Broker。
一般我们在实际应用中,都会关闭重回队列,也就是设置为false。
//生产端代码
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/"); Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel(); String exchange = "test_ack_exchange";
String routingKey = "ack.save"; for(int i =0; i<5; i ++){ Map<String, Object> headers = new HashMap<String, Object>();
headers.put("num", i); AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
.deliveryMode(2)
.contentEncoding("UTF-8")
.headers(headers)
.build();
String msg = "Hello RabbitMQ ACK Message " + i;
channel.basicPublish(exchange, routingKey, true, properties, msg.getBytes());
}
//消费端代码
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/"); Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel(); String exchangeName = "test_ack_exchange";
String queueName = "test_ack_queue";
String routingKey = "ack.#"; channel.exchangeDeclare(exchangeName, "topic", true, false, null);
channel.queueDeclare(queueName, true, false, false, null);
channel.queueBind(queueName, exchangeName, routingKey); // 手工签收 必须要关闭 autoAck = false
channel.basicConsume(queueName, false, new MyConsumer(channel));
//自定义消费者
private Channel channel ; public MyConsumer(Channel channel) {
super(channel);
this.channel = channel;
} @Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.err.println("-----------consume message----------");
System.err.println("body: " + new String(body));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if((Integer)properties.getHeaders().get("num") == 0) {
channel.basicNack(envelope.getDeliveryTag(), false, true);
} else {
channel.basicAck(envelope.getDeliveryTag(), false);
} }
TTL队列/消息
TTL是time to live的缩写,也就是生存时间
RabbitMQ支持消息的过期时间,在消息发送时可以进行指定
RabbitMQ支持队列的过期时间,从消息入队列开始计算,只要超过了队列的超过时间配置,那么消息会自动的清除。

消息10s过期,TTL是队列过期时间。
DLX死信队列
DLX,Dead-Letter-Exchange
利用DLX,当消息在一个队列中变成死信之后,它能够被重新publish到另一个exchange,这个exchange就是DLX。
消息变成死信情况:
消息被拒绝(basic.reject/basic.nack)并且request=false
消息TTL过期
队列达到最大的长度
DLX也是一个正常的exchange,和一般的exchange没有区别,他能在任何的队列上被指定,实际上就是设置某个队列的属性。
当这个队列中有死信时,RabbitMQ就会自动的将这个消息重新发布到设置的exchange上去,进而被路由到另一个队列。
可以监听这个队列中消息做相应的处理,这个特性可以弥补RabbitMQ3.0以前支持的immediate参数的功能。
死信队列设置:
首先要设置死信队列的exchange和queue,然后进行绑定:
Exchange:dlx.exchange
Queue:dlx.queue
RoutingKey:#
然后我们进行正常声明交换机,队列,绑定,只不过我们需要在队列加上一个参数:arguments.put("x-dead-letter-exchange","dlx.exchange");
这样消息在过期、request、队列子啊达到最大长度时, 消息就可以直接路由到死信队列。
//生产者端代码
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
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, true, properties, msg.getBytes());
}
//消费者端代码
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
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));
//自定义消费者
public MyConsumer(Channel channel) {
super(channel);
} @Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.err.println("-----------consume message----------");
System.err.println("consumerTag: " + consumerTag);
System.err.println("envelope: " + envelope);
System.err.println("properties: " + properties);
System.err.println("body: " + new String(body));
}
RabbitMQ消费端ACK与重回队列机制,TTL,死信队列详解(十一)的更多相关文章
- 消费端ACK和重回队列
使用场景 消费端ACK和重回队列 消费端ACK使用场景: 1.消费端进行消费的时候,如果由于业务异常我们可以进行日志记录,然后进行补偿. 2.由于服务器宕机等严重问题,那我们就需要手工进行ACK保障消 ...
- RabbitMQ 消费端限流、TTL、死信队列
目录 消费端限流 1. 为什么要对消费端限流 2.限流的 api 讲解 3.如何对消费端进行限流 TTL 1.消息的 TTL 2.队列的 TTL 死信队列 实现死信队列步骤 总结 消费端限流 1. 为 ...
- RabbitMQ 入门系列:9、扩展内容:死信队列:真不适合当延时队列。
系列目录 RabbitMQ 入门系列:1.MQ的应用场景的选择与RabbitMQ安装. RabbitMQ 入门系列:2.基础含义:链接.通道.队列.交换机. RabbitMQ 入门系列:3.基础含义: ...
- python中利用队列asyncio.Queue进行通讯详解
python中利用队列asyncio.Queue进行通讯详解 本文主要给大家介绍了关于python用队列asyncio.Queue通讯的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细 ...
- 服务端捡起或丢弃指定物品ID触发详解
传奇服务端捡起或丢弃指定物品ID触发详解: @PickUpItemsX X是物品数据库中对应的IDX@DropItemsX X是物品数据库中对应的IDX@H.PickUpItemsX X是物品数据库中 ...
- RabbitMQ消费端消息的获取方式(.Net Core)
1[短链接]:BasicGet(String queue, Boolean autoAck) 通过request的方式独自去获取消息,断开式,一次次获取,如果返回null,则说明队列中没有消息. 隐患 ...
- RabbitMQ消费端限流策略(十)
消费端限流: 什么是消费端限流? 场景: 我们RabbitMQ服务器有上万条未处理的消息,我们随便打开一个消费者客户端,会出现下面情况: 巨量的消息瞬间全部推送过来,但是我们单个客户端无法同时处理这么 ...
- RabbitMQ消费端自定义监听(九)
场景: 我们一般在代码中编写while循环,进行consumer.nextDelivery方法进行获取下一条消息,然后进行消费处理. 实际环境: 我们使用自定义的Consumer更加的方便,解耦性更强 ...
- RabbitMQ与.net core(四) 消息的优先级 与 死信队列
1.消息的优先级 假如现在有个需求,我们需要让一些优先级最高的通知推送到客户端,我们可以使用redis的sortedset,也可以使用我们今天要说的rabbit的消息优先级属性 Producer代码 ...
随机推荐
- Linux运维的第三周总结
01. 下列文件中, 包含了主机名到IP地址的映射关系的文件是() A. /etc/HOSTNAME B. /etc/hosts C. /etc/resolv.conf ...
- Hive-生成一个大文件(小文件合并)
set hive.execution.engine=mr; --在 map-reduce 作业结束时合并小文件.如启用,将创建 map-only 作业以合并目标表/分区中的文件. set hive.m ...
- Nginx服务器优势是什么
nginx介绍.功能,优势 https://www.cnblogs.com/wcwnina/p/8728391.html#!comments Nginx负载均衡,session共享问题,几种解决方案 ...
- Centos中使用Docker部署Apollo
采用微服务开发框架开发项目时会涉及多个系统,如果要更改配置参数需要在多个系统间逐一更改,比较费时,而且容易遗漏,效率低下,次问题可以采用Apollo配置中心的方式解决,下面将介绍如何配置: 准备环境: ...
- 为什么 Java 线程没有 Running 状态?
Java虚拟机层面所暴露给我们的状态,与操作系统底层的线程状态是两个不同层面的事.具体而言,这里说的 Java 线程状态均来自于 Thread 类下的 State 这一内部枚举类中所定义的状态: 什么 ...
- win10无法开启网络发现怎么办 如何启用网络发现
鼠标右键点击桌面左下角的开始按钮,在弹出的菜单中选择“运行”菜单项. 在打开的Windows10运行窗口中,输入Services.msc,然后点击确定按钮. 在打开的Windows10服务窗口 ...
- oracle数据的导入导出(两种方法三种方式)
大概了解数据库中数据的导入导出.在oracle中,导入导出数据的方法有两种,一种是使用cmd命令行的形式导入导出数据,另一种是使用PL/SQL工具导入导出数据. 1,使用cmd命令行导入导出数据 1. ...
- Hive导入导出数据的方法
Hive导入数据的方式 官网文档: LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (p ...
- 【转】/etc/inittab文件详解
转自:https://www.cnblogs.com/ricks/p/10020886.html Linux在完成核内引导(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就 ...
- java并发学习--第八章 JDK 8 中线程优化的新特性
一.新增原子类LongAdder LongAdder是JDK8中AtomicLong的增强工具类,它与AtomicLong最大的不同就是:在多线程场景下,LongAdder中对单一的变量进行拆分成多个 ...