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代码 ...
随机推荐
- 五、Zabbix-自动注册
一.Zabbix Serber 1.进入动作界面 配置—>动作—>事件源—>自动注册—>创建动作 2.配置自动注册动作 1.配置动作 2.配置操作 Next step 添加成功 ...
- MySQL的事务和视图
事务 1.概念 一条或者多条sql语句的集合! 事务:就是一堆操作的集合,他们同生共死.要么都执行成功,要么都执行失败2.事务的特性 ACID A:原子性 完整的,不可分割的 原子性 (Atom ...
- JProfiler监控
原文: https://blog.csdn.net/jijilan/article/details/83022715
- Kotlin学习(5)类型系统
可空性(避免空指针异常) /* *这个函数的参数代表传入一个String类型变量的实例,这代表它不可以为空 */ fun a(str:String){ println(str) } //这样调用a() ...
- textarea标签输出内容时不能顶格(左对齐)输出
我用textarea输出文本内容的时候出现下面的问题:文本内容在action里测试没有问题(文本内容前面没有空格),但是在jsp页面textare标签中输出文本内容时,文本内容前面却出现一些多余的空格 ...
- Vue 中如何定义全局的变量和常量
Vue 中如何定义全局的变量和常量 我想要定义一个变量, 在项目的任何地方都可以访问到, 不需要每一次使用的时候, 都引入. 尝试1:创建 global.js 并且在其中定义 let a = 10 ...
- vue 项目报错,提示:Cannot read property '$createElement' of undefined at render ...
vue 项目报错,提示:Cannot read property '$createElement' of undefined at render ...
- Android 点击跳转到蓝牙设置界面
不再重写一遍了,看csdn: https://blog.csdn.net/qq_42866164/article/details/101353709
- KVC,KVO详解
Key Value Coding Key Value Coding是cocoa的一个标准组成部分,它能让我们可以通过name(key)的方式访问property, 不必调用明确的property ac ...
- MATLAB的边缘检测函数中隐含的细化(非极大值抑制)算法
前段时间做了一个车牌检测识别的项目,我的任务是将MATLAB中的算法移植成C++代码.在车牌区域提取的过程中,用到了水平方向的Sobel算子检测垂直边缘,一开始我直接把MATLAB中的 bw = ed ...