微服务
RabbitMQ
同步通讯的优缺点
优点:
时效性较强,可以立即得到结果
问题:
- 耦合度高,每次加入新的需求都要修改原来的代码
- 性能和吞吐能力下降,如果调用链过长则响应时间等于每次调用的时间之和
- 资源浪费:调用链中的每个服务在等待响应过程中,不能释放请求占用的资源,高并发场景下会极度浪费系统资源
- 级联失败:如果服务提供者出现问题,所有调用方都会跟着出现问题
异步调用方案
异步调用常见实现就是事件驱动模式
异步通信的优点:
- 耦合度低
- 吞吐量提升
- 故障隔离
- 流量削峰
缺点:
- 依赖于Broker的可靠性、安全性、吞吐能力
- 架构复杂了,业务没有明显的流程线,不好追踪管理
MQ
中文是消息队列,字面来看就是存放消息的队列。也就是时间驱动架构中的Broker。
RabbitMQ安装与运行
安装:
docker pull rabbitmq
运行:
docker run \
-e RABBITMQ_DEFAULT_USER=itcast \
-e RABBITMQ_DEFAULT_PASS=123321 \
--name mq \
--hostname mq1 \
-p 15672:15672 \
-p 5672:5672 \
-d \
rabbitmq:latest
-e:给mq设置环境变量
–name:起名
–hostname :主机名 单机不用配置,集群需要配置
-p :端口映射
-d:后台运行
消息模型
MQ的官方文档中给了5个MQ的Demo示例,对应了几种不同的用法:
- 基本消息队列(BasicQueue)
- 工作消息队列(WorkQueue)
- 发布订阅,有根据交换机类型不同分三种:
- Fanout Exchange:广播
- Direct Exchange:路由
- Topic Exchange:主题
HelloWorld案例
官方的HelloWorld是基于最基础的消息队列模型来实现的,只包括三个角色:
- publisher:消息发布者,将消息发送到队列queue
- queue:消息队列,负责接收并缓存消息
- consumer:订阅队列,处理队列中的消息
完成官方中的Demo工程
基本消息队列的消息发送流程:
- 建立connection
- 创建channel
- 利用channel声明队列
- 利用channel向队列发送消息
基本消息队列的消息接收流程:
- 建立connection
- 创建channel
- 利用channel声明队列
- 定义consumer的消费行为handleDelivery()
- 利用channel将消费者与队列绑定
SpringAMQP
- Basic Queue 简单队列模型
- Work Queue 工作队列模型
- 发布、订阅模型-Fanout
- 发布、订阅模型-Direct
- 发布、订阅模型-Topic
- 消息转换器
什么是SpringAMQP
使用SpringAMQP实现HelloWorld中的基础啊请问色天涯DR·SAdytufirg+ohthptt【消息队列功能
流程如下:
- 在父工程中引入spring-amqp依赖
- 在publisher服务中利用RabbitTemplate发送消息到simple.queue这个队列
- 在consumer服务中编写消费逻辑,绑定simple.queue这个队列
什么是AMQP?
应用间消息通信的一种协议,与语言和平台无关
SpringAMQP如何发送消息?
引入amqp的starter依赖
配置RabbitMQ的地址
利用RabbitTemplate的convertAndSend方法
SpringAMQP如何接收消息?
引入amqp的starter依赖
配置RabbitMQ的地址
定义类添加@Component注解
类中声明方法,添加@RabbitListener注解,方法参数就是消息
ps:消息一旦消费就会从队列中删除,RabbitMQ没有消息回溯功能
模拟WorkQueue,实现一个队列绑定多个消费者
基本思路如下:
- 在publisher服务中定义测试方法,每秒产生50条消息,发送到simple.queue
- 在consumer服务中定义两个消息监听者,都监听simple.queue队列
- 消费者1每秒处理50条消息,消费者2每秒处理10条消息
Work模型的使用
- 多个消费者绑定到一个队列,同一条消息只会被一个消费者处理
- 通过设置prefetch来控制消费者预取的消息数量
发布(publish)、订阅(subscribe)
发布订阅模式与之前案例的区别就是允许将同一消息发给多个消费者。实现方式是加入了交换机(exchange)
交换机的作用是什么?
- 接收publisher发送的消息
- 将消息按照规则路由到与之绑定的队列
- 不能缓存消息,路由失败,路由丢失
- FanoutExchange的会将消息路由到每个绑定的队列
声明队列、交换机、绑定关系的Bean是什么?
- Queue
- FanoutExchange
- Binding
发布订阅-DirectExchange
Direct Exchange会将接收到的消息根据规则路由到指定的Queue,因此称为路由模式(routes)
- 每一个Queue都与Exchange设置一个BindingKey
- 发布者发送消息时,指定消息的RoutingKey
- Exchange将消息路由到BindingKey与消息RoutingKey一致的队列
FanoutExchange
描述下Direct交换机与Fanout交换机的差异?
- Fanout交换机将消息路由给每一个与之绑定的队列
- Direct交换机根据RoutingKey判断路由给哪个队列
- 如果多个队列具有相同的RoutingKey,则与Fanout功能类似
基于@RabbitListener注解声明队列和交换机有哪些常见注解?
- @Queue
- @Exchange
TopicExchange
描述下Direct交换机与Topic交换机的差异
Topic交换机支持通配符,BindingKey支持通配符,RoutingKey以.分割,#支持一个或多个,*代表恰好一个
消息转换器
SpringAMQP中消息的序列化和反序列化是怎么实现的?
- 利用MessageConverter实现的,默认是JDK的序列化
- 注意发送方与接收方必须使用相同的MessageConverter