rabbitmq的高级特性:

  如何保障消息的百分之百成功?

  要满足4个条件:生产方发送出去,消费方接受到消息,发送方接收到消费者的确认信息,完善的消费补偿机制

  解决方案,1)消息落库,进行消息状态打标

  该解决方案需要对对数据库进行两次io操作,如果数据量很大,将会导致瓶颈的发生,本流程是首先将业务入库,发送消息前,将发送的消息入库消息状态可设置为0,两次写入数据库后,发送消息,消息发送后,mq broker 接收并处理消息,完成后发送回馈消息确认信息,同过确认监听服务器,监听到确认消息后,将其数据库状态更改为1,说明消息发送成功,但是过程中可能出现各种情况导致不能反馈消息,我们需要在添加一个定时轮询任务,比如说设置最大轮询次数为3,时间间隔为5min,每一次当超过5分钟就去检查一次数据库消息状态,如果还是0则,再次发送消息,知道消息状态变为1为止。

  2)延迟投递,二次确认,回调检查

  该模式适用于高并发的场景,也就是并发量非常的,对系统性能要求较高的场合,该模式减少一次主业务的io操作,首先业务落库,然后生成两条消息,首先发出去一次消息,然后5min之后再次发送消息(延迟投递),第一条发送后,broker端收到后转给消费端,正常处理后,发送一个相应消息(再次生成一条的消息)投递出去step4:send confirm,发送到callback服务中,如果callback服务收确认消息,那么callback将消息写入数据库,5min后发送的第二条消息,进入broker中,此时,broker将消息投递到callback中的监听,收到后检查数据库,如果检查消息已经存在,说明消费者正常消费,如果,因各种情况发现消费者没有正产消费,那么callback要进行补偿,发起一个RPC通信告诉上游说消息发送失败,上游程序再次生成消息,重新走上述流程。

幂等性:在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。消息重复投递,或者高并发下,消息仅仅消费一次。

消息确认模式:

生产方:

 package com.zxy.demo.rabbitmq;

 import java.io.IOException;
import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; public class Producter { public static void main(String[] args) throws IOException, TimeoutException {
// TODO Auto-generated method stub
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.10.110");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");
Connection conn = factory.newConnection();
Channel channel = conn.createChannel();
String exchange001 = "exchange_001";
String queue001 = "queue_001";
String routingkey = "mq.topic";
String body = "hello rabbitmq!";
// 添加消息确认模式========消息确认模式重要添加
channel.confirmSelect();
channel.basicPublish(exchange001, routingkey, null, body.getBytes());
// 添加一个确认监听========消息确认模式重要添加
channel.addConfirmListener(new ConfirmListener() { @Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
System.out.println("-----------nck------------"+deliveryTag); } @Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
System.out.println("-----------ck------------"+deliveryTag); }
});
} }

消费方:

 package com.zxy.demo.rabbitmq;

 import java.io.IOException;
import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; public class Receiver { public static void main(String[] args) throws IOException, TimeoutException {
// TODO Auto-generated method stub
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.10.110");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");
Connection conn = factory.newConnection();
Channel channel = conn.createChannel();
String exchange001 = "exchange_001";
String queue001 = "queue_001";
String routingkey = "mq.*";
channel.exchangeDeclare(exchange001, "topic", true, false, null);
channel.queueDeclare(queue001, true, false, false, null);
channel.queueBind(queue001, exchange001, routingkey);
// 自定义消费者
MyConsumer myConsumer = new MyConsumer(channel);
// 进行消费(消费queue001队列中的消息进行消费,签收模式为自动签收,消费的具体处理类是myConsumer)
channel.basicConsume(queue001, true, myConsumer);
} }

自定义消费类:

 package com.zxy.demo.rabbitmq;

 import java.io.IOException;

 import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope; /**
* 可以继承,可以实现,实现的话要覆写的方法比较多,所以这里用了继承
*
*/
public class MyConsumer extends DefaultConsumer{
private Channel channel;
public MyConsumer(Channel channel) {
super(channel);
// TODO Auto-generated constructor stub
this.channel=channel;
} @Override
public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body)
throws IOException {
System.out.println("消费标签:"+consumerTag);
System.out.println("envelope.getDeliveryTag():==="+envelope.getDeliveryTag());
System.out.println("envelope.getExchange():==="+envelope.getExchange());
System.out.println("envelope.getRoutingKey():==="+envelope.getRoutingKey());
System.out.println("body:==="+new String(body));
} }

确认模式,主要点有两个,一、在channel上添加确认模式channel.comfirmSelect(),

二、添加确认监听器,实现AK和NAK两个方法来处理两种返回情况。

返回模式大同小异:返回模式需要在发布消息时

采用含有mandatory(托管、强制)参数的消息发布模式,并设置该参数为true========这个与消息确认模式有所区别

true则当消息不可达返回处理消息,如果为false则消息不可达删除消息
channel.basicPublish(exchange001, routingkey, true, null, body.getBytes());

然后添加一个返回监听处理没有正确路由的消息,该监听需要实现处理消息的方法。

这两个模式区别较小,消费端没有什么特别的主要是如果返回模式,路由键让其路由不到消费队列即可使返回监听有动作。

代码如下,仅贴出生产端代码,消费如上:

 package com.zxy.demo.rabbitmq;

 import java.io.IOException;
import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.ReturnListener;
import com.rabbitmq.client.AMQP.BasicProperties; public class Producter { public static void main(String[] args) throws IOException, TimeoutException {
// TODO Auto-generated method stub
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.10.110");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");
Connection conn = factory.newConnection();
Channel channel = conn.createChannel();
String exchange001 = "exchange_001";
String queue001 = "queue_001";
String routingkey = "mq.topic.return";
String body = "hello rabbitmq!===============返回模式";
// 采用含有mandatory(托管、强制)参数的消息发布模式,并设置该参数为true========这个与消息确认模式有所区别
channel.basicPublish(exchange001, routingkey, true, null, body.getBytes());
// 添加一个返回监听========消息返回模式重要添加
channel.addReturnListener(new ReturnListener() { @Override
public void handleReturn(int replyCode,
String replyText,
String exchange,
String routingKey,
AMQP.BasicProperties properties,
byte[] body)
throws IOException {
System.out.println("=============return 模式============");
System.out.println("replyCode:"+replyCode+"\n"
+"replyText:"+replyText+"\n"
+"exchange:"+exchange+"\n"
+"routingKey:"+routingKey+"\n"
+"properties:"+properties.getBodySize()+"\n"
+"body:"+new String(body)+"\n"); }
});
} }

Rabbitmq之高级特性——百分百投递消息&消息确认模式&消息返回模式实现的更多相关文章

  1. RabbitMQ的高级特性概念理解

    1.RabbitMQ中的消息如何保障百分之百的投递成功? 答:百分之百的投递成功,方案可以参考下面的2.3. 2.什么是生产者端的可靠性投递? 答:第一步,生产者保障消息的成功发出.第二步,保障Rab ...

  2. RabbitMQ:消息发送确认 与 消息接收确认(ACK)

    默认情况下如果一个 Message 被消费者所正确接收则会被从 Queue 中移除 如果一个 Queue 没被任何消费者订阅,那么这个 Queue 中的消息会被 Cache(缓存),当有消费者订阅时则 ...

  3. Rabbitmq的高级特性

    消息如何保证100%投递成功? 什么是生产端的可靠性投递? 1.保障消息的成功发出 2.保障MQ节点的成功接收 3.发送端收到MQ节点(Broker)确认应答 4.完善的消息补偿机制 BAT互联网大厂 ...

  4. Rabbitmq之高级特性——实现消费端限流&NACK重回队列

    如果是高并发下,rabbitmq服务器上收到成千上万条消息,那么当打开消费端时,这些消息必定喷涌而来,导致消费端消费不过来甚至挂掉都有可能. 在非自动确认的模式下,可以采用限流模式,rabbitmq ...

  5. SpringCloud(六) - RabbitMQ安装,三种消息发送模式,消息发送确认,消息消费确认(自动,手动)

    1.安装erlang语言环境 1.1 创建 erlang安装目录 mkdir erlang 1.2 上传解压压缩包 上传到: /root/ 解压缩# tar -zxvf otp_src_22.0.ta ...

  6. java消息服务学习之JMS高级特性

    将介绍的内容是: 控制消息确认.为发送消息指定选项.创建临时目的地.使用JMS本地事务.异步发送消息 五个方面. 1.控制消息确认 在JMS消息得到确认之前,并不认为它已经成功使用.要成功使用消息,通 ...

  7. 消息中间件——RabbitMQ(七)高级特性全在这里!(上)

    前言 前面我们介绍了RabbitMQ的安装.各大消息中间件的对比.AMQP核心概念.管控台的使用.快速入门RabbitMQ.本章将介绍RabbitMQ的高级特性.分两篇(上/下)进行介绍. 消息如何保 ...

  8. RabbitMQ(二):RabbitMQ高级特性

    RabbitMQ是目前非常热门的一款消息中间件,不管是互联网大厂还是中小企业都在大量使用.作为一名合格的开发者,有必要了解一下相关知识,RabbitMQ(一)已经入门RabbitMQ,本文介绍Rabb ...

  9. 消息中间件——RabbitMQ(八)高级特性全在这里!(下)

    前言 上一篇消息中间件--RabbitMQ(七)高级特性全在这里!(上)中我们介绍了消息如何保障100%的投递成功?,幂等性概念详解,在海量订单产生的业务高峰期,如何避免消息的重复消费的问题?,Con ...

随机推荐

  1. 5(计算机网络)从物理层到MAC层

    故事就从我的大学宿舍开始讲起吧.作为一个八零后,我要暴露年龄了. 我们宿舍四个人,大一的时候学校不让上网,不给开通网络.但是,宿舍有一个人比较有钱,率先买了一台电脑.那买了电脑干什么呢? 首先,有单机 ...

  2. jmeter学习笔记一foreach控制器

    ForEach控制器 输入变量前缀:上一步所提取的变量名的前缀,例如appid_1, 则appid就是前缀 start index for loop:循环的起始位置,默认为空也可 end index ...

  3. phpcms安装与使用

    安装完wamp(或phpstudy)之后,将phpcms的安装文件复制入C:\wamp\www(或C:\phpStudy\PHPTutorial\WWW)文件夹下: 打开phpcms_v9_UTF8\ ...

  4. 三 基于Java数组手写循环队列

    Code: package dataStucture2.stackandqueue; /** * 手写循环队列 * * @param <E> */ public class MyLoopQ ...

  5. Django(二十)分页:

    一.知识点 参考:https://docs.djangoproject.com/zh-hans/3.0/topics/pagination/ 查询出所有省级地区的信息,显示在页面上. AeroInfo ...

  6. Python 数组

    使用之前要先导入函数库  import numpy as np 数组名=np.zeros(数组大小,数据类型)    初始化为0值,这里的数据类型只能是数值类型,字符类型不能用 一.一维数组 impo ...

  7. springMVC List对象转换为json列表对象

    @ResponseBody @RequestMapping("xxx.do") public List<POJO> getList(){ return List< ...

  8. oracle数据库时间是毫秒值,创建function,直接SQL取值。

    首先创建一个function: create or replace function num_to_date(in_number NUMBER) return date is begin return ...

  9. Adroid ViewPage+GridView实现每页6个元素,三页滑动切换

    //}//public class MainActivity extends Activity {// private static final float APP_PAGE_SIZE = 16.0f ...

  10. Linux centos7 日常运维——使用w查看系统负载、vmstat命令、top命令、sar命令、nload命令

    一.使用w查看系统负载 w .uptime查看系统负载,0.00表示1分钟之内负载为0 cat  /proc/cpuinfo查看cpu核数 二.vmstat命令,查看进程.cpu.memory.交换. ...