相关文章:
SpringAMQP 快速入门
RabbitMQ 如何保证消息可靠性
微服务一旦拆分,必然涉及到服务之间的相互调用,之前讲到的基于 OpenFeign 的调用。这种调用中,调用者发起请求后需要等待服务提供者执行业务返回结果后,才能继续执行后面的业务。也就是说调用者在调用过程中处于阻塞状态,因此我们称这种调用方式为同步调用,也可以叫同步通讯。但在很多场景下,我们可能需要采用异步通讯的方式,为什么呢?
两种方式的区别:
两种方式各有优劣,打电话可以立即得到响应,但是你却不能跟多个人同时通话。发微信可以同时与多个人收发微信,但是往往响应会有延迟。
所以,如果我们的业务需要实时得到服务提供方的响应,则应该选择同步通讯(同步调用)。而如果我们追求更高的效率,并且不需要实时响应,则应该选择异步通讯(异步调用)。
我们以注册成功后邮件通知为例
同步调用的业务流程是:
这样的业务流程会存在下面三个问题
一、性能低
由于同步调用,调用者需要等待服务提供者执行完返回结果后,才能继续向下执行,也就是说每次远程调用,调用者都是阻塞等待状态。最终整个业务的响应时长就是每次远程调用的执行时长之和:100+100+300+50 = 550ms
二、扩展性差
比如需要添加短信通知,需要在代码中添加短信服务的远程调用代码。
三、级联失效
在这个案例中,注册成功了,但是邮件通知服务出现了问题抛出了错误会让存入数据库的信息回滚导致整个注册业务失败。
需要解决这些问题就需要用异步调用的方式来代替同步调用。
异步调用方式其实就是基于消息通知的方式,一般包含三个角色:
在异步调用中,发送者不再直接同步调用接收者的业务接口,而是发送一条消息投递给消息Broker。然后接收者根据自己的需求从消息Broker那里订阅消息。每当发送方发送消息后,接受者都能获取消息并处理。
这样,发送消息的人和接收消息的人就完全解耦了。
还是以注册通知为例:
将远程调用逻辑删除,改为发送一条消息到Broker。而相关的微服务都可以订阅消息通知,一旦消息到达Broker,则会分发给每一个订阅了的微服务,处理各自的业务。
后续需要添加短信通知也只需要添加一个短信服务订阅消息即可。
而且注册服务的耗时也和其他服务无关。
综上,异步调用的优势包括:
当然,异步通信也并非完美无缺,它存在下列缺点:
消息Broker,目前常见的实现方案就是消息队列(MessageQueue),简称为MQ.
目比较常见的MQ实现:
几种常见MQ的对比:
RabbitMQ | ActiveMQ | RocketMQ | Kafka | |
---|---|---|---|---|
公司/社区 | Rabbit | Apache | 阿里 | Apache |
开发语言 | Erlang | Java | Java | Scala&Java |
协议支持 | AMQP,XMPP,SMTP,STOMP | OpenWire,STOMP,REST,XMPP,AMQP | 自定义协议 | 自定义协议 |
可用性 | 高 | 一般 | 高 | 高 |
单机吞吐量 | 一般 | 差 | 高 | 非常高 |
消息延迟 | 微秒级 | 毫秒级 | 毫秒级 | 毫秒以内 |
消息可靠性 | 高 | 一般 | 高 | 一般 |
追求可用性:Kafka、 RocketMQ 、RabbitMQ
追求可靠性:RabbitMQ、RocketMQ
追求吞吐能力:RocketMQ、Kafka
追求消息低延迟:RabbitMQ、Kafka
RabbitMQ 是一个开源的消息中间件(Message Broker),用于在分布式系统中传递消息。它实现了高级消息队列协议(AMQP),这是一种网络协议,用于在应用程序之间传递消息。
以下是 RabbitMQ 的一些主要特性和概念:
这里介绍 Docker 安装 RabbitMQ 的过程。
2.1.1 拉取镜像
docker pull rabbitmq:management # 拉取带有web界面的镜像
2.1.2 启动容器
docker run -e RABBITMQ_DEFAULT_USER=root -e RABBITMQ_DEFAULT_PASS=root --name mq --hostname q -p 15672:15672 -p 5672:5672 -d rabbitmq:management
# -e RABBITMQ_DEFAULT_USER=root 用户名
# -e RABBITMQ_DEFAULT_PASS=root 密码
端口介绍:
2.1.3 访问管理页面
http://ip地址:15672
RabbitMQ对应的架构如图:
其中包含几个角色:
publisher
:生产者,也就是发送消息的一方consumer
:消费者,也就是消费消息的一方queue
:队列,存储消息。生产者投递的消息会暂存在消息队列中,等待消费者处理exchange
:交换机,负责消息路由。生产者发送的消息由交换机决定投递到哪个队列。virtual host
:虚拟主机,起到数据隔离的作用。每个虚拟主机相互独立,有各自的exchange、queue打开Exchanges
选项,可以看到RabbitMQ预定义了7种交换机,这7种交换机有4种类型。
关于交换机类型的简介:
Direct Exchange(直连交换机):
直连交换机是最简单的交换机类型。
它将消息路由到与消息中的路由键完全匹配的队列中。
在消息生产者指定的路由键和队列的绑定键完全相同时,消息将被发送到相应的队列。
Fanout Exchange(扇出交换机):
Topic Exchange(主题交换机):
*
(匹配一个单词)和 #
(匹配零个或多个单词),允许更复杂的路由规则。Headers Exchange(头交换机):
关于预定义的7种交换机简介:
打开Queues
选项卡,新建一个队列:
点击 amq.fanout
交换机
绑定队列 queue1
点击 amq.fanout
交换机
发送消息
队列成功收到消息
RabbitMQ 使用 virtual host 实现数据隔离
新建一个虚拟主机
添加一个用户
现在用户test还没有能访问的虚拟主机
切换登录用户test后无法获取没有访问权限的虚拟主机的队列消息。
点击test为用户添加虚拟主机
右上角 虚拟主机切换为 /test 看不到其他虚拟主机的消息队列,这就是基于virtual host
的隔离效果。