三.防止消息丢失
来源:互联网 发布:蜂窝数据快捷开关 编辑:程序博客网 时间:2024/05/27 20:07
提供者和消费者的pom.xml和上一章一样
RabbitMQ中,消息丢失可以简单的分为两种:客户端丢失和服务端丢失。针对这两种消息丢失,RabbitMQ都给出了相应的解决方案。
默认情况下,RabbitMQ会平均的分发消费给多个消费者,假设一个消费者任务的执行时间非常长,在执行过程中,客户端挂了(连接断开),那么,该客户端正在处理且未完成的消息,以及分配给它还没来得及执行的消息,都将丢失。因为默认情况下,RabbitMQ分发完消息后,就会从内存中把消息删除掉。
解决方法:消息确认:
RabbitMQ引入了消息确认机制,当消息处理完成后,给Server端发送一个确认消息,来告诉服务端可以删除该消息了,如果连接断开的时候,Server端没有收到消费者发出的确认信息,则会把消息转发给其他保持在线的消费者。
上代码:
一.Producer提供者:
1.发送消息的类
2.测试启动发送小的Main
和上一章的提供者一样
二.Consumer消费者
1.消费者的类:MessageRecive.java
分两个部分,重现消息丢失的情况和解决方案
package com.rabbitmq.consumer;import java.io.IOException;import java.util.concurrent.TimeoutException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import com.rabbitmq.client.AMQP;import com.rabbitmq.client.Channel;import com.rabbitmq.client.Connection;import com.rabbitmq.client.ConnectionFactory;import com.rabbitmq.client.Consumer;import com.rabbitmq.client.DefaultConsumer;import com.rabbitmq.client.Envelope;public class MessageRecive { private Logger logger = LoggerFactory.getLogger(MessageRecive.class); //测试客户端丢失消息的情况,设置10秒处理事件,处理的时候强制关闭 public boolean lostMessageConsumer(String queueName){ //连接rabbitmq ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = null; Channel channel =null; //声明消费的queue try { connection = factory.newConnection(); channel = connection.createChannel(); channel.queueDeclare(queueName,false,false,false,null); //这里重写了DefaultConsumer的handleDelivery方法,因为发送的时候对消息进行了getByte(),在这里要重新组装成String Consumer consumer = new DefaultConsumer(channel){ //重写父类方法 @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)throws IOException { String message = new String(body, "UTF-8"); logger.info("接收到:" + message); //休眠10秒,模拟10秒处理事件 try { logger.info("开始处理消息(休眠)......"); Thread.sleep(10000); System.out.println("处理完毕!"); } catch (Exception e) { // TODO: handle exception } } }; //上面是声明消费者,这里用 声明的消费者 消费 列队的消息 System.out.println("开始等待提供者的消息...."); //自动应答,消费者自动应答给提供者(手动应答为false,需要开发者手动应答) boolean autoAck = true; channel.basicConsume(queueName, autoAck,consumer); //这里不能关闭连接,调用了消费方法后,消费者会一直连接着rabbitMQ等待消费 } catch (Exception e) { logger.error("出现异常:"+e); return false; } return true; } //解决客户端丢失消息的情况,设置10秒处理事件,处理的时候强制关闭(原理:消息确认机制) /** * RabbitMQ引入了消息确认机制,当消息处理完成后,给Server端发送一个确认消息, * 来告诉服务端可以删除该消息了,如果连接断开的时候,Server端没有收到消费者发 * 出的确认信息,则会把消息转发给其他保持在线的消费者。 * @param queueName * @return */ public boolean resolveLostMessageConsumer(String queueName){ //连接rabbitmq ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); try { Connection connection = factory.newConnection(); //解决内部类只能访问final修饰的局部变量 final Channel channel = connection.createChannel(); //声明消费的queue channel.queueDeclare(queueName,false,false,false,null); //在消息确认之前,不在处理其他消息 //prefetchCount:会告诉RabbitMQ不要同时给一个消费者推送多于N个消息,即一旦有N个消息还没有ack,则该consumer将block掉,直到有消息ack channel.basicQos(1); //这里重写了DefaultConsumer的handleDelivery方法,因为发送的时候对消息进行了getByte(),在这里要重新组装成String(局部内部类) Consumer consumer = new DefaultConsumer(channel){ //重写父类方法 @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)throws IOException { String message = new String(body, "UTF-8"); logger.info("接收到:" + message); //休眠10秒,模拟10秒处理事件 try { logger.info("开始处理消息(休眠)......"); Thread.sleep(10000); System.out.println("处理完毕!"); } catch (Exception e) { // TODO: handle exception }finally { //手动应答,告诉服务器可以删除消息,否则不删除或给其他消费者 /** * @param deliveryTag the tag from the received 这个是RabbitMQ用来区分消息的,文档在这(https://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.deliver.delivery-tag) * @param multiple true to acknowledge all messages up to and 为true的话,确认所有消息,为false只确认当前消息 */ channel.basicAck(envelope.getDeliveryTag(), false); } } }; //上面是声明消费者,这里用 声明的消费者 消费 列队的消息 System.out.println("开始等待提供者的消息...."); //关闭自动应答(接收到消息提供者就删除消息),改为手动应答,很重要 boolean autoAsk = false; channel.basicConsume(queueName, autoAsk,consumer); //这里不能关闭连接,调用了消费方法后,消费者会一直连接着rabbitMQ等待消费 } catch (Exception e) { logger.error("出现异常:"+e); return false; } return true; }}
2.测试消息丢失的情况的Main:LostMessageMain.java
package com.rabbitmq.main;import com.rabbitmq.consumer.MessageRecive;public class LostMessageMain { //从哪个列队取消息 private final static String QUEUE_NAME = "hello"; //测试客户端丢失消息的情况,当程序正在执行时,出现异常(强制中断程序),正在处理的和等待处理的消息都会丢失 public static void main(String[] args) { MessageRecive messageRecive = new MessageRecive(); messageRecive.lostMessageConsumer(QUEUE_NAME); }}
当程序执行到一般时强制关闭程序,然后在到RabbitMq的消息列队中查看消息(http://localhost:15672/),发现列队要发给此消费者的消息s已经被删除。
3.测试解决消息丢失(消息确认)的Main:ResolveLostMessageMain.java
package com.rabbitmq.main;import com.rabbitmq.consumer.MessageRecive;public class ResolveLostMessageMain { //指定需要消费哪个列队的消息 private static final String QUEUE_NAME = "hello"; //解决客户端消息丢失的方法(消息确认机制),生产两条消息,执行时强制关闭程序,发现消息还在 //如果有其他消费者,会发送给其他消费者 /** * RabbitMQ引入了消息确认机制,当消息处理完成后,给Server端发送一个确认消息, * 来告诉服务端可以删除该消息了,如果连接断开的时候,Server端没有收到消费者发 * 出的确认信息,则会把消息转发给其他保持在线的消费者。 * 自动确认:接收到消息后就向提供者发送确认消息,提供者就删除消息 * 手动确认:开发者认为消息处理完毕手动向提供者发送确认消息,提供者才从列队删除消息 * */ public static void main(String[] args) { MessageRecive messageRecive = new MessageRecive(); messageRecive.resolveLostMessageConsumer(QUEUE_NAME); }}
当消息执行到一半,强制关闭程序,再去查看列队消息,发现此消费者的消息s都还在,如果有多个消费者 ,其中一个消费者挂掉了,mq不会删除列队的消息,会发送给其他消费者消费。
- 三.防止消息丢失
- RabbitMQ 防止消息丢失
- RabbitMQ防止消息丢失
- 在openfire中添加消息队列,防止聊天信息丢失方法
- WebBrowser 防止section丢失
- 防止Session丢失
- session 转移防止丢失
- PHP防止精度丢失
- 防止异常丢失
- 使用rowversion防止更新丢失
- 如何防止网站数据丢失
- asp.net 防止session丢失
- kafka consumer防止数据丢失
- kafka consumer防止数据丢失
- 防止消息钩子入侵
- RFC516 丢失消息的检测
- 多线程:PostThreadMessage 消息可能会丢失
- ZeroMQ之消息丢失解决方法
- 安装activiti
- linux rm 命令(删除文件和目录)
- Java8 新特性
- Insert Sort
- 安装MYSQL出错:a windows service with the name MYSQL already...service.
- 三.防止消息丢失
- [前端与移动开发] 如何在面试中争取高薪
- Linux下的进程间通信-详解
- SAE J1939协议
- github代码上传(window10版本)
- nginx源码学习4——重写共享内存锁类
- D_D系统构建-MBR(3)代码
- myeclipse+mysql+apache安装地址共享
- 【知识库】--Dubbo ReferenceBean获取-- 调用RegistryDirectory.notify -- 源码过程(254)