1.同步和异步介绍
在了解什么事消息队列之前,我们要先知道同步和异步通讯的区别,我们从以下两方面介绍MQ:
- 同步和异步通讯
- 什么使用MQ
1.1. 同步和异步通讯
微服务之间的通讯方式有同步和异步两种方式:
- 同步通讯:实现方式OpenFegin,就像打电话,实时响应,同时不能和两个人通话
- 异步通讯:实现方式MQ(消息队列),就像发邮件,或者微信聊天,可以同时和多人交流,并且不需要对方马上回复
两种方式各有优劣,同步方式,需要立即得到响应,但是不能同时和多个微服务进行通讯,异步方式可以同时和多个微服务进行交互,但是响应会有延迟。
1.1.1.同步通讯
通过上面介绍我们已经知道,SpringCloud中的OpenFegin技术就是同步通讯方式,虽然OpenFegin调用微服务可以进行实时响应,但是也存在以下很多问题:
- 耦合度高:每一次加入新的需求,都需要修改原有代码
- 性能下降: 调用者需要等待服务提供者响应,如果服务链过长,那么每次响应时间等于调用时间之和
- 资源浪费: 服务链中的每个服务等待响应过程,不能释放请求,就会占用资源,在高并发情况下就会形成资源浪费
- 级联失败: 如果服务提供者存在问题,那么所有调用该服务的调用者都会出现问题,最终可能导致整个微服务集群出现故障
总结:
同步调用的优点:
- 时效性较强,可以立即得到结果
同步调用的问题:
- 耦合度高
- 性能和吞吐能力下降
- 有额外的资源消耗
- 有级联失败问题
1.1.2. 异步通讯
异步通讯,我们今天要介绍的MQ技术就是常用实现方式之一,他避免了同步调用出现的问题。
举例说明:
当小伙伴在京东购买商品,在我们支付的时候,同时会异步调用订单服务修改订单状态,调用库存服务减少库存个数,同时也调用物流服务准备发货。
我们可以将支付服务看做事件发布者(publisher),在支付完成后只需要发布一个支付成功的事件(event),事件中带上订单id。订单服务、库存服务和物流服务看做事件订阅者(Consumer),订阅支付成功的事件,监听到事件后完成自己业务即可。
为了解除事件发布者与订阅者之间的耦合,两者并不是直接通信,而是有一个中间人(Broker)。发布者发布事件到Broker,不关心谁来订阅事件。订阅者从Broker订阅事件,不关心谁发来的消息。
Broker 是一个像数据总线一样的东西,所有的服务要接收数据和发送数据都发到这个总线上,这个总线就像协议一样,让服务间的通讯变得标准和可控。
好处:
- 吞吐量提升:无需等待订阅者处理完成,响应更快速
- 故障隔离:服务没有直接调用,不存在级联失败问题
- 调用间没有阻塞,不会造成无效的资源占用
- 耦合度极低,每个服务都可以灵活插拔,可替换
- 流量削峰:不管发布事件的流量波动多大,都由Broker接收,订阅者可以按照自己的速度去处理事件
缺点:
- 架构复杂了,业务没有明显的流程线,不好管理
- 需要依赖于Broker的可靠、安全、性能
通过介绍异步通讯,以及优点后,我们大概也就知道为什么使用MQ了,那么现在我们就具体介绍一下,为什么使用消息服务器托管网队列。
2.为什么使用消息队列
使用消息队列的场景会很多,但是主要作用就是以下三点:
- 解耦
- 异步
- 削峰
2.1 解耦
我们还以购物商品为例,支付服务需要发生订单id到订单和物流两个服务,通过使用OpenFegin,进行数据发送,那么现在如果新增了库存服务,也需要支付服务的订单id,或者说订单服务取消了,那么支付服务是不是都要通过不断地修改服务代码进行实现,思考一下如果你是支付服务负责人,你会不会发狂。
在购买商品的这个场景中,支付服务和其他服务因为同步调用,存在了严重的系统耦合,支付服务产生一条订单数据,其他相关联的需要订单ID的服务,就需要支付服务发生数据过去,并且此时我们还需要考虑如果和支付服务相关联的服务挂掉,那么我们怎么办?如果高并发情况下会产生什么后果?是不是可能发生所有和支付相关联的服务最终都会挂掉
如果使用 MQ,支付服务产生一条订单数据,发送到 MQ 里面去,哪个系统需要数据自己去 MQ 里面消费。如果新系统需要数据,直接从 MQ 里消费即可;如果某个系统不需要这条数据了,就取消对 MQ 消息的消费即可。这样下来,支付服务压根儿不需要去考虑要给谁发送数据,不需要维护这个代码,也不需要考虑人家是否调用成功、失败超时等情况。
总结:
通过一个 MQ,Pub/Sub 发布订阅消息这么一个模型,支付服务就跟其它系统彻底解耦了
2.2. 异步
还是购买商品场景,不过我们从另外一个角度来分析,支付服务接受支付请求,需要在自己本地写库,还需要在 订单、物流和库存 三个服务写库,自己本地写库要 50ms,订单、物流和库存 三个服务分别写库要 159ms、350ms、450ms。最终请求总延时是 50 + 150 + 350 + 450 = 1000ms,也就是 1s,用户感觉这是什么烂系统,慢的要死。用户通过浏览器发起请求,等待个 1s,这几乎是不可接受的。
一般互联网类的企业,对于用户直接的操作,一般要求是每个请求都必须在 200 ms 以内完成,对用户几乎是无感知的。
如果使用 MQ,那么支付服务连续发送消息到 MQ 队列中,假如耗时 20ms,支付服务从接受一个请求到返回响应给用户,总时长是 50+ 20 = 70ms,对于用户而言,其实感觉上就是点个按钮,70ms 以后就直接返回了,爽!网站做得真好,真快!
2.3. 削峰
在每年的双十一促销活动期间,用户量会急剧增加,导致系统的并发请求压力大幅上升。
- 首先,当用户下单时,订单服务将订单信息发送到消息队列中,而不是立即处理该订单。这样订单服务快速地返回响应给用户,表示订单已经成功接收。
- 然后,支付服务作为一个消费者订阅了订单队列,并从队列中接收订单消息。支付服务根据接收到的订单信息进行支付处理,并将支付结果发送到支付结果队列中。
- 同时,库存服务也作为一个消费者订阅了订单队列,从队列中接收订单消息。库存服务根据接收到的订单信息,检查商品库存情况,如果库存充足,则进行扣减,并将扣减结果发送到库存结果队列中。
- 最后,物流服务作为一个消费者订阅了库存结果队列,从队列中接收库存扣减结果消息。如果库存扣减成功,则物流服务开始准备发货并将物流跟踪号发送给用户。
3.MQ技术实现对比
MQ,中文是消息队列(MessageQueue),字面来看就是存放消息的队列。也就是事件驱动架构中的Broker。
比较常见的MQ实现:
- ActiveMQ
- RabbitMQ
- RocketMQ
- Kafka
几种常见MQ的对比:
RabbitMQ |
ActiveMQ |
RocketMQ |
Kafka |
|
公司/社区 |
Rabbit |
Apache |
阿里 |
Apache |
开发语言 |
Erlang |
Java |
Java |
Scala&Java |
协议支持 |
AMQP,XMPP,SMTP,STOMP |
OpenWire,STOMP,REST,XMPP,AMQP |
自定义协议 |
自定义协议 |
可用性 |
高,基于主从架构实现高可用 |
同 RabbitMQ |
非常高,分布式架构 |
非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
单机吞吐量 |
万级,比 RocketMQ、Kafka 低一个数量级 |
同 ActiveMQ |
10 万级,支撑高吞吐 |
10 万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景 |
消息延迟 |
微秒级 |
毫秒级 |
毫秒级 |
毫秒以内 |
消息可靠性 |
高(基本不丢) |
一般(有较低的概率丢失数据) |
高(经过参数优化配置,可以做到 0 丢失) |
一般(同 RocketMQ) |
- 追求可用性:Kafka、 RocketMQ 、RabbitMQ
- 追求可靠性:RabbitMQ、RocketMQ
- 追求吞吐能力:RocketMQ、Kafka
- 追求消息低延迟:RabbitMQ、Kafka
总结:中小型公司,技术实力较为一般,技术挑战不是特别高,用 RabbitMQ 是不错的选择;大型公司,基础架构研发实力较强,用 RocketMQ 是很好的选择。
如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用服务器托管网,北京机房租用,IDC机房托管, http://www.fwqtg.net