RabbitMQ入门案例 - Simple 简单模式
https://www.bilibili.com/video/BV1dX4y1V73G?p=44
实现步骤
- jdk1.8
- 构建一个 maven工程
- 导入 rabbitmq的 maven依赖
- 启动 rabbitmq-server服务
- 定义生产者
- 定义消费者
- 观察消息的在 rabbitmq-server服务中的进程
构建一个maven工程
导入依赖
java原生依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.10.0</version>
</dependency>
第一种模型
在上图的模型中,有以下概念:
- 生产者,也就是要发送消息的程序
- 消费者:消息的接受者,会一直等待消息到来。
- 消息队列:图中红色部分。类似一个邮箱,可以缓存消息;生产者向其中投递消息,消费者从其中取出消息。
生产者
//简单模式
public class Producer{
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("10.15.0.9");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");
Connection connection = connectionFactory.newConnection("生产者");
//2.创建通道
Channel channel = connection.createChannel();
//3.通过创建交换机,声明队列,绑定关系,路由key,发送消息和接受消息
/*参数1: 是否持久化,非持久化消息会存盘吗?会存盘,但是会随着重启服务器而丢失
参数2:是否独占队列
参数3:是否自动删除,随着最后一个消费者消息完毕消息以后是否把队列自动删除
参数4:携带附属属性
*/
String queueName = "queue1";
channel.queueDeclare(queueName,false,false,false,null);
//4.发送消息给队列queue
/*参数1: 交换机
参数2:队列、路由key
参数3:消息的状态控制
参数4:消息主题
*/
//面试题:可以存在没有交换机的队列吗?不可能,虽然没有指定交换机但是一定会存在一个默认的交换机
String message = "Hello";
channel.basicPublish("",message, null,message.getBytes());
//5.关闭
channel.close();
connection.close();
}
消费者
//简单模式
public class Consumer{
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("10.15.0.9");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");
Connection connection = connectionFactory.newConnection("生产者");
//2.创建通道
Channel channel = connection.createChannel();
//3.接受内容
channel.basicConsume("queue1",true,new DefaultConsumer(){
public void handle(String consumerTag, Delivery message) throws IOException {
System.out.println(new String("收到消息是" + new String(meassage.getBody()),"UTF-8"));
},new CancelCallback(){
public void handle(String consumerTag) throws IOException {
System.out.println("接受失败了");
}
});
//4.关闭
channel.close();
connection.close();
}
什么是AMQP
什么是AMQP
AMQP全称:Advanced Message Queuing Protocol(高级消息队列协议)。是应用层协议的一个开发标准,为面向消息的中间件设计
AMQP生产者流转过程
AMQP消费者流转过程
RabbitMQ的核心组成部分
RabbitMQ的核心组成部分
RabbitMQ整体架构是什么样子的?
RabbitMQ的运行流程
RabbitMQ支持的消息模型
- 简单模式 Simple
- 工作模式 Work
- 发布订阅模式
- 路由模式
- 主题 Topic模式
- 参数模式
RabbitMQ入门案例 - fanout 模式
RabbitMQ的模式之发布订阅模式
图解
发布订阅模式的具体实现
- web操作查看视频
- 类型:fanout
- 特点:Fanout - 发布与订阅模式,是一种广播机制,它是没有路由 key的模式
生产者
//简单模式
public class Producer{
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("10.15.0.9");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");
Connection connection = connectionFactory.newConnection("生产者");
//2.创建通道
Channel channel = connection.createChannel();
//3.通过创建交换机,声明队列,绑定关系,路由key,发送消息和接受消息
/*参数1: 是否持久化,非持久化消息会存盘吗?会存盘,但是会随着重启服务器而丢失
参数2:是否独占队列
参数3:是否自动删除,随着最后一个消费者消息完毕消息以后是否把队列自动删除
参数4:携带附属属性
*/
String queueName = "queue1";
channel.queueDeclare(queueName,false,false,false,null);
//4.发送消息给队列queue
/*参数1: 交换机
参数2:队列、路由key
参数3:消息的状态控制
参数4:消息主题
*/
//面试题:可以存在没有交换机的队列吗?不可能,虽然没有指定交换机但是一定会存在一个默认的交换机
String message = "Hello";
//5.准备交换机
String exchangeName = "fanout-exchange";
//6.定义路由key
String routeKey = "";
//7.指定交换机的类型
String type = "fanout";
channel.basicPublish(exchangeName,routeKey, null,message.getBytes());
//8.关闭
channel.close();
connection.close();
}
消费者
代码一样,使用线程启动测试而已!
此处没有通过代码去绑定交换机和队列,而是通过可视化界面去绑定的!
RabbitMQ入门案例 - Direct 模式
//6.定义路由key
String routeKey = "email";
//7.指定交换机的类型
String type = "direct";
channel.basicPublish(exchangeName,routeKey, null,message.getBytes());
RabbitMQ入门案例 - Topic 模式
//6.定义路由key
String routeKey = "com.order.test.xxx";
//7.指定交换机的类型
String type = "direct";
channel.basicPublish(exchangeName,routeKey, null,message.getBytes());
代码创建及绑定
//5.准备交换机
String exchangeName = "direct_message_exchange";
String exchangeType = "direct";
//如果你用界面把queue和exchange的关系先绑定话,代码就不需要在编写这些声明代码可以让代码变得更简洁
//如果用代码的方式去声明,我们要学习一下
//6.声明交换机 所谓的持久化就是指,交换机会不会随着服务器重启造成丢失
channel.exchangeDeclare(exchangeName,exchangeType,true);
//7.声明队列
channel.queueDeclare("queue5",true,false,false,null);
channel.queueDeclare("queue6",true,false,false,null);
channel.queueDeclare("queue7",true,false,false,null);
//8.绑定队列和交换机的关系
channel.queueBind("queue5",exchangeName,"order");
channel.queueBind("queue6",exchangeName,"order");
channel.queueBind("queue7",exchangeName,"course");
channel.basicPublish(exchangeName,course, null,message.getBytes());
RabbitMQ入门案例 - Work模式
Work模式轮询模式(Round-Robin)
图解
当有多个消费者时,我们的消息会被哪个消费者消费呢,我们又该如何均衡消费者消费信息的多少呢?
主要有两种模式:
- 轮询模式的分发:一个消费者一条,按均分配
- 公平分发:根据消费者的消费能力进行公平分发,处理快的处理的多,处理慢的处理的少;按劳分配
生产者
跟简单模式一样!
消费者
创建两个一样的!
Work模式公平分发模式
生产者
跟简单模式一样!
消费者
//简单模式
public class Consumer{
//3.接受内容
//指标定义出来
channel.basicQos(1);
channel.basicConsume("queue1",false,new DefaultConsumer(){
public void handle(String consumerTag, Delivery message) throws IOException {
System.out.println(new String("收到消息是" + new String(meassage.getBody()),"UTF-8"));
//改成手动应答
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
},new CancelCallback(){
public void handle(String consumerTag) throws IOException {
System.out.println("接受失败了");
}
});
//4.关闭
channel.close();
connection.close();
}
创建两个一样的!
RabbitMQ使用场景
解耦、削峰、异步
同步异步的问题(串行)
串行方式:将订单信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端
public void makeOrder(){
//1.发送订单
//2.发送短信服务
//3.发送email服务
//4.发送app服务
}
并行方式 异步线程池
并行方式:将订单信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间
public void test(){
//异步
theadpool.submit(new Callable<Object>{
//1.发送短信服务
})
//异步
theadpool.submit(new Callable<Object>{
//2.
})
//异步
theadpool.submit(new Callable<Object>{
//3.
})
//异步
theadpool.submit(new Callable<Object>{
//4.
})
}
存在问题
- 耦合度高
- 需要自己写线程池自己维护成本太高
- 出现了消息可能会丢失,需要你自己做消息补偿
- 如何保证消息的可靠性你自己写
- 如果服务器承载不了,你需要自己去写高可用
异步消息队列的方式
好处:
- 完全解耦,用 MQ建立桥接
- 有独立的线程池和运行模型
- 出现了消息可能会丢失,MQ有持久化功能
- 如何保证消息的可靠性,死信队列和消息转移等
- 如果服务器承载不了,你需要自己去写高可用,HA镜像模型高可用
按照以上约定,用户的响应时间相当于是订单信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20QPS。比串行提高了3倍,比并行提高了两倍
高内聚,低耦合
好处:
- 完全解耦,用 MQ建立桥接
- 有独立的线程池和运行模型
- 出现了消息可能会丢失,MQ有持久化功能
- 如何保证消息的可靠性,死信队列和消息转移等
- 如果服务器承载不了,你需要自己去写高可用,HA镜像模型高可用
按照以上约定,用户的响应时间相当于是订单信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20QPS。比串行提高了3倍,比并行提高了两倍
高内聚,低耦合
[外链图片转存中…(img-kyL4Icya-1615906714948)]
[外链图片转存中…(img-bqSYfEx2-1615906714950)]