本文已参与「新人创作礼」活动,一起开启掘金创作之路。
面试复习。加油。
写在前面
推荐
服务异步通信RabbitMQ
初识MQ
同步通讯
微服务间基于Feign的调用就属于同步方式,存在一些问题。
同步调用存在的问题
耦合度高,违反开闭原则
1
# 同步调用的优点:
2
时效性较强,可以立即得到结果
3
4
# 同步调用的问题:
5
耦合度高
6
性能和吞吐能力下降
7
有额外的资源消耗
8
有级联失败问题
异步通讯
异步调用常见实现就是事件驱动模式

1
# 异步通信的优点:
2
耦合度低
3
吞吐量提升
4
故障隔离
5
流量削峰
6
7
# 异步通信的缺点:
8
依赖于Broker的可靠性、安全性、吞吐能力
9
架构复杂了,业务没有明显的流程线,不好追踪管理
MQ常见框架
MQ (MessageQueue),中文是消息队列,字面来看就是存放消息的队列。也就是事件驱动架构中的Broker。
RabbitMQ快速入门
RabbitMQ概述和安装(可靠性、稳定性、高可用)
RabbitMQ是基于Erlang语言开发的开源消息通信中间件,官网地址:www.rabbitmq.com/
可以基于docker安装
各个用户虚拟主机进行隔离
1
# RabbitMQ中的几个概念:
2
channel:操作MQ的工具
3
exchange:路由消息到队列中
4
queue:缓存消息
5
virtual host:虚拟主机,是对queue、exchange等资源的逻辑分组
常见消息模型
MQ的官方文档中给出了5个MQ的Demo示例,对应了几种不同的用法:
前两种不是完整的消息驱动模型
快速入门 HelloWorld案例
官方的HelloWorld是基于最基础的消息队列模型来实现的,只包括三个角色:
- publisher:消息发布者,将消息发送到队列queue
- queue:消息队列,负责接受并缓存消息
- consumer:订阅队列,处理队列中的消息
实现步骤:
- 导入课前资料中的demo工程
- 运行publisher服务中的测试类PublisherTest中的测试方法testSendMessage()
- 查看RabbitMQ控制台的消息
- 启动consumer服务,查看是否能接收消息
1
# 基本消息队列的消息发送流程:
2
建立connection
3
创建channel
4
利用channel声明队列
5
利用channel向队列发送消息
6
7
# 基本消息队列的消息接收流程:
8
建立connection
9
创建channel
10
利用channel声明队列
11
定义consumer的消费行为handleDelivery()
12
利用channel将消费者与队列绑定
SpringAMQP
SpringAmqp的官方地址:spring.io/projects/sp…
Basic Queue 简单队列模型
利用SpringAMQP实现HelloWorld中的基础消息队列功能
流程如下:
步骤1:在父工程中引入spring-amqp的依赖
因为publisher和consumer服务都需要amqp依赖,因此这里把依赖直接放到父工程mq-demo中
步骤2:在publisher服务中利用RabbitTemplate发送消息到simple.queue这个队列(使用很优雅)
在consumer服务中编写消费逻辑,绑定simple.queue这个队列
1
# 什么是AMQP?
2
应用间消息通信的一种协议,与语言和平台无关。
3
4
# SpringAMQP如何发送消息?
5
引入amqp的starter依赖
6
配置RabbitMQ地址
7
利用RabbitTemplate的convertAndSend方法
8
9
# SpringAMQP如何接收消息?
10
引入amqp的starter依赖
11
yml配置RabbitMQ地址
12
定义类,添加@Component注解
13
类中声明方法,添加@RabbitListener注解,方法参数就是消息
14
注意:消息一旦消费就会从队列删除,RabbitMQ没有消息回溯功能
Work Queue 工作队列模型
Work queue,工作队列,可以提高消息处理速度,避免队列消息堆积
模拟WorkQueue,实现一个队列绑定多个消费者
1
基本思路如下:
2
在publisher服务中定义测试方法,每秒产生50条消息,发送到simple.queue
3
在consumer服务中定义两个消息监听者,都监听simple.queue队列
4
消费者1每秒处理50条消息,消费者2每秒处理10条消息
步骤1:生产者循环发送消息到simple.queue
在publisher服务中添加一个测试方法,循环发送50条消息到simple.queue队列
步骤2:编写两个消费者,都监听simple.queue
在consumer服务中添加一个消费者,也监听simple.queue:
消费预取限制
修改application.yml文件,设置preFetch这个值,可以控制预取消息的上限:
1
Work模型的使用:
2
多个消费者绑定到一个队列,同一条消息只会被一个消费者处理
3
通过设置prefetch来控制消费者预取的消息数量
发布、订阅模型-Fanout
发布订阅模式与之前案例的区别就是允许将同一消息发送给多个消费者。实现方式是加入了exchange(交换机)。
常见exchange类型包括:
- Fanout:广播
- Direct:路由
- Topic:话题
注意:exchange负责消息路由,而不是存储,路由失败则消息丢失
Fanout Exchange 会将接收到的消息广播到每一个跟其绑定的queue
利用SpringAMQP演示FanoutExchange的使用
1
# 实现思路如下:
2
在consumer服务中,利用代码声明队列、交换机,并将两者绑定
3
在consumer服务中,编写两个消费者方法,分别监听fanout.queue1和fanout.queue2
4
在publisher中编写测试方法,向itcast.fanout发送消息
步骤1:在consumer服务声明Exchange、Queue、Binding
SpringAMQP提供了声明交换机、队列、绑定关系的API,例如:
在consumer服务创建一个类,添加@Configuration注解,并声明FanoutExchange、Queue和绑定关系对象Binding,代码如下:
步骤2:在consumer服务声明两个消费者
在consumer服务的SpringRabbitListener类中,添加两个方法,分别监听fanout.queue1和fanout.queue2:
步骤3:在publisher服务发送消息到FanoutExchange
在publisher服务的SpringAmqpTest类中添加测试方法:
1
# 交换机的作用是什么?
2
接收publisher发送的消息
3
将消息按照规则路由到与之绑定的队列
4
不能缓存消息,路由失败,消息丢失
5
FanoutExchange的会将消息路由到每个绑定的队列
6
7
# 声明队列、交换机、绑定关系的Bean是什么?
8
Queue
9
FanoutExchange
10
Binding
发布、订阅模型-Direct
# Direct Exchange 会将接收到的消息根据规则路由到指定的Queue,因此称为路由模式(routes)。
每一个Queue都与Exchange设置一个BindingKey
发布者发送消息时,指定消息的RoutingKey
Exchange将消息路由到BindingKey与消息RoutingKey一致的队列
利用SpringAMQP演示DirectExchange的使用
# 描述下Direct交换机与Fanout交换机的差异?
Fanout交换机将消息路由给每一个与之绑定的队列
Direct交换机根据RoutingKey判断路由给哪个队列
如果多个队列具有相同的RoutingKey,则与Fanout功能类似
# 基于@RabbitListener注解声明队列和交换机有哪些常见注解?
@Queue
@Exchange
发布、订阅模型-Topic消息转换器
1
TopicExchange与DirectExchange类似,区别在于routingKey必须是多个单词的列表,并且以 . 分割。
2
Queue与Exchange指定BindingKey时可以使用通配符:
3
#:代指0个或多个单词
4
*:代指一个单词
china.news 代表有中国的新闻消息;
china.weather 代表中国的天气消息;
japan.news 则代表日本新闻
japan.weather 代表日本的天气消息;
1
# SpringAMQP中消息的序列化和反序列化是怎么实现的?
2
利用MessageConverter实现的,默认是JDK的序列化
3
注意发送方与接收方必须使用相同的MessageConverter
\