后端的同步与异步之间的关系

同步调用


我们现在基于OpenFeign的调用都属于是同步调用,那么这种方式存在哪些问题呢?

举个例子,我们以余额支付功能为例来分析,首先看下整个流程:

mid1目前我们采用的是基于OpenFeign的同步调用,也就是说业务执行流程是这样的:

  • 支付服务需要先调用用户服务完成余额扣减

  • 然后支付服务自己要更新支付流水单的状态

  • 然后支付服务调用交易服务,更新业务订单状态为已支付

三个步骤依次执行,是一个同步的状态,这其中就存在3个问题。

第一:拓展性差

我们目前的业务相对简单,但是随着业务规模扩大,产品的功能也在不断完善,最终你的支付业务会越来越臃肿

mid1
也就是说每次有新的需求,现有支付逻辑都要跟着变化,代码经常变动,不符合开闭原则,拓展性不好。

第二:性能下降

由于我们采用了同步调用,调用者需要等待服务提供者执行完返回结果后,才能继续向下执行,也就是说每次远程调用,调用者都是阻塞等待状态。最终整个业务的响应时长就是每次远程调用的执行时长之和。

mid1

假如每个微服务的执行时长都是50ms,则最终整个业务的耗时可能高达300ms,性能太差了。

第三:级联失败

由于我们是基于OpenFeign调用交易服务、通知服务。当交易服务、通知服务出现故障时,整个事务都会回滚,交易失败。

但是大家思考一下,我们假设用户余额充足,扣款已经成功,此时我们应该确保支付流水单更新为已支付,确保交易成功。毕竟收到手里的钱没道理再退回去吧。

因此,这里不能因为短信通知、更新订单状态失败而回滚整个事务。

而要解决这些问题,我们就必须用异步调用的方式来代替同步调用

注意:同步的优势

用户扣除余额后,才能更新交易流水,这种核心业务必须是同步的,异步无法保证任务完成的顺序。

mid1

异步调用

异步调用的优势包括:

  • 耦合度更低
  • 性能更好
  • 业务拓展性强
  • 故障隔离,避免级联失败

异步调用的优势缺点:

  • 完全依赖于Broker的可靠性、安全性和性能
  • 架构复杂,后期维护和调试麻烦

异步调用方式其实就是基于消息通知的方式,一般包含三个角色:

  • 消息发送者:投递消息的人,就是原来的调用方

  • 消息Broker(代理):管理、暂存、转发消息,你可以把它理解成微信服务器

  • 消息接收者:接收和处理消息的人,就是原来的服务提供方

enter image description here
在异步调用中,发送者不再直接同步调用接收者的业务接口,而是发送一条消息投递给消息Broker。然后接收者根据自己的需求从消息Broker那里订阅消息。每当发送方发送消息后,接受者都能获取消息并处理。

这样,发送消息的人和接收消息的人就完全解耦了。

还是以余额支付业务为例:

enter image description here
除了扣减余额、更新支付流水单状态以外,其它调用逻辑全部取消。而是改为发送一条消息到Broker。而相关的微服务都可以订阅消息通知,一旦消息到达Broker,则会分发给每一个订阅了的微服务,处理各自的业务。

我们可以很轻松的去扩展异步的业务:

enter image description here
不管后期增加了多少消息订阅者,作为支付服务来讲,执行问扣减余额、更新支付流水状态后,发送消息即可。业务耗时仅仅是这三部分业务耗时,仅仅100ms,大大提高了业务性能。

另外,不管是交易服务、通知服务,还是积分服务,他们的业务与支付关联度低。现在采用了异步调用,解除了耦合,他们即便执行过程中出现了故障,也不会影响到支付服务。

常见的异步中间技术选型


消息 Broker,目前常见的实现方案就是消息队列(Message Queue),简称 MQ。

目前比较常见的 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 自定义协议 自定义协议
可用性 一般
单机吞吐量 一般 非常高
消息延迟 微秒级 毫秒级 毫秒级 毫秒以内
消息可靠性 一般 一般

根据不同需求选择 MQ:

  1. 追求可用性:Kafka、RocketMQ、RabbitMQ
  2. 追求可靠性:RabbitMQ、RocketMQ
  3. 追求吞吐能力:RocketMQ、Kafka
  4. 追求消息低延迟:RabbitMQ、Kafka

根据统计,目前国内消息队列使用最多的还是 RabbitMQ。RabbitMQ 各方面比较均衡,稳定性较好,因此本课程将选择 RabbitMQ 来学习。