这一部分的笔记是比较粗略的,原因是我之前学过一遍RabbitMq,所以就快速的跟着视频复习了一遍,然后我之前有总结RabbitMQ常用的命令和集群方面的搭建。参考我这篇文章:
RabbitMQ个人总结
1. 初识MQ
同步通讯和异步通讯
手机通讯无法同时跟多人打电话,微信聊天可以同时跟多个人聊天
同步调用
微服务间基于Feign的调用就属于同步方式,存在一些问题:
- 耦合度高:每次加入新的需求,都要修改原来的代码
- 性能下降:调用者需要等待服务提供者响应,如果调用链过长则响应时间等于每次调用的时间之和。
- 资源浪费:调用链中的每个服务在等待响应过程中,不能释放请求占用的资源,高并发场景下会极度浪费系统资源
- 级联失败:如果服务提供者出现问题,所有调用方都会跟着出问题,如同多米诺骨牌- -样,迅速导致整个微服务群故障
总结
同步调用的优点:
- 时效性较强,可以立即得到结果
同步调用的问题:
- 耦合度高
- 性能和吞吐能力下降
- 有额外的资源消耗
- 有级联失败问题
异步调用
异步调用常见实现就是事件驱动模式
优势
-
服务解耦
-
性能提升,吞吐量提高
-
服务没有强依赖,不担心级联失败问题(故障隔离)
-
流量削峰
缺点:
-
依赖于Broker的可靠性、安全性、吞吐能力
-
架构复杂了,业务没有明显的流程线,不好追踪管理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1axMra5k-1637069883227)(https://gitee.com/zuckdbg/zuckpicbed/raw/master/img/image-20211116155345031.png)]
什么是MQ
MQ (MessageQueue), 中文是消息队列, 字面来看就是存放消息的队列。也就是事件驱动架构中的Broker。
国内常用RabbitMQ 和 Kafka , Kafka适用于数据安全要求不高的,海量数据,(如日志)
RabbitMQ和 RocketMQ 稳定性更强,可靠性更高,吞吐量不差,适用于稳定性要求高的业务之间的通信。
中小型企业-RabbitMQ,无深度定制要求。
2.RabbitMQ快速入门
RabbitMQ是基于Erlang语言开发的开源消息通信中间件,官网地址: https://www.rabbitmq.com/
1. 单机部署
我们在Centos7虚拟机中使用Docker来安装。
1.下载镜像
方式一:在线拉取
docker pull rabbitmq:3-management
方式二:从本地加载
在课前资料已经提供了镜像包:
上传到虚拟机中后,使用命令加载镜像即可:
docker load -i mq.tar
# 查看docker images 发现导入成功
rabbitmq 3-management 95bc78c8d15d 17 months ago 187MB
2.安装MQ
docker run \
-e RABBITMQ_DEFAULT_USER=root \
-e RABBITMQ_DEFAULT_PASS=123456 \
--name mq \
--hostname mq1 \
-p 15672:15672 \
-p 5672:5672 \
-d \
rabbitmq:3-management
3.访问
http://192.168.10.100:15672
2.RabbitMQ的结构和概念
RabbitMQ中的几个概念:
- channel: 操作MQ的工具
- exchange: 路由消息到队列中
- queue: 缓存消息
- virtual host:虚拟主机,是对queue、 exchange等资源的逻辑分组
3.消息模型
官方的HelloWorld是基于最基础的消息队列模型来实现的,只包括三个角色:
publisher:消息发布者,将消息发送到队列queue
queue:消息队列,负责接受并缓存消息
consumer:订阅队列,处理队列中的消息
4.入门案例
3.SpringAMQP
3.1 发送消息
步骤一:
在mq-demo项目的父工程pom.xml引入以下依赖:
<!--AMQP依赖,包含RabbitMQ-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
步骤2:
在publisher中编写测试方法,向simple.queue发送消息
总结:
什么是AMQP?
应用间消息通信的一种协议,与语言和平台无关。
SpringAMQP如何发送消息?
引入amqp的starter依赖,配置RabbitMQ地址
利用RabbitTemplate的convertAndSend方法
3.2 接收消息
启动Consumer服务
SpringAMQP如何接收消息?
- 引入amqp的starter依赖
- 配置RabbitMQ地址
- 定义类,添加@Component注解
- 类中声明方法,添加@RabbitListener注解,方法参数就时消息
3.3 WorkQueue工作队列
@Test
public void testSendMsgWorkQueue() throws InterruptedException {
String queueName = "simple.queue";
String message = "hello,message __ ";
for (int i = 1; i <= 50; i++) {
rabbitTemplate.convertAndSend(queueName,message + i);
Thread.sleep(20);
}
}
package cn.itcast.mq.listener;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @author:whd
* @createTime: 2021/11/16
*/
@Component
public class SpringRabbitListener {
// @RabbitListener(queues = "simple.queue")
// public void listenSimpleQueueMessage(String msg) {
// System.out.println("spring消费者接收到消息:【" + msg + "]");
// }
//记录消费者1的消费量
private Integer count1 = 0;
//记录消费者2的消费量
private Integer count2 = 0;
/**
* 消费者1,每秒50条消息
* @param msg
*/
@RabbitListener(queues = "simple.queue")
public void listen1WorkQueueMessage(String msg) throws InterruptedException {
count1++;
System.out.println("消费者1【处理能力强】接收到消息:【" + msg + "】,当前是消费者1的第"+count1+"条");
Thread.sleep(20);
}
/**
* 消费者2,每秒10条消息
* @param msg
*/
@RabbitListener(queues = "simple.queue")
public void listen2WorkQueueMessage(String msg) throws InterruptedException {
count2++;
System.err.println("消费者2【处理能力强】接收到消息:【" + msg + "】,当前是消费者2的第"+count2+"条");
Thread.sleep(100);
}
}
但是怎么让消费能力弱的少拿点消息呢?
3.4 消费预取限制
能提高消息处理速度,这个执行以后,消费者1能力强拿到的消息多(40条),消费者2能力弱拿到的消息少(10条)
3.5 发布订阅模型
1.Fanout Exchange
Fanout Exchange会将接收到的消息路由到每一个跟其绑定的queue
交换机的作用是什么?
- 接收publisher发送的消息
- 将消息按照规则路由到与之绑定的队列
- 不能缓存消息,路由失败,消息丢失
- FanoutExchange的会将消息路由到每个绑定的队列
声明队列、交换机、绑定关系的Bean是什么?
- Queue
- FanoutExchange
- Binding
2.Direct Exchange
使用注解方式绑定队列与交换机,并声明bindingkey
描述下Direct交换机与Fanout交换机的差异?
- Fanout交换机将消息路由给每一个与之绑定的队列
- Direct交换机根据RoutingKey判断路 由给哪个队列
- 如果多个队列具有相同的RoutingKey,则与Fanout功能类似
基于@RabbitListener注解声明队列和交换机有哪些常见注解?
@Queue
@Exchange
3.Topic Exchange
描述下Direct交换机与Topic交换机的差异?
Topic支持通配符
3.6 消息转换器
依赖也可以是:jackson核心依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
总结
思考一下,这种基于MQ的异步通知操作,在哪些业务场景中可以用到呢?