微服务间通讯有两种方式:

  • 同步通讯:实时响应。
  • 异步通讯:不需要马上回复。

两种方式各有优劣,同步通讯可以立即得到响应,但是却不能跟多个服务同时通讯。异步通讯可以同时与多个服务通讯,但是往往响应会有所延迟。


同步通讯

Feign调用就属于同步方式,虽然调用可以实时得到结果,但存在下面的问题:

  • 耦合度高:消费者与提供者之间存在直接的调用关系。在服务中每次加入新的需求,都要修改原来的代码。
  • 性能下降:消费者需要等待提供者响应,如果调用链过长,响应时间等于每次调用的时间之和。
  • 资源浪费:消费者在等待响应过程中,不能释放请求占用的资源,高并发场景下会极度浪费系统资源。
  • 级联失败:如果提供者出现问题,所有消费者都会跟着出问题。如同多米话骨牌一样,迅速导致整个微服务群故障。

还有一个导致性能下降和资源浪费的原因:消费者在给提供者发请求时,提供者在处理别的消费者的请求,无法及时响应,这也会导致该消费者等待过长时间的响应。

同步通讯并非只有缺点没有优点,其优点为时效性较强,可以立即得到结果。


异步通讯

异步调用可以避免上述同步通讯时造成的问题。

在异步通讯中,使用事件Event)和代理Broker)处理通讯。在异步通讯中有三种角色:

  • 事件发布者Publisher):Publisher在处理完自己的业务后,发布一个事件给Broker。
  • 事件代理者Broker):Borker在接收到Publisher的事件消息后,将该消息发送给订阅了该事件的Consumer。
  • 事件订阅者Consumer):Consumer接收到自己订阅的事件消息后,根据事件做相应的业务处理。并且Consumer可以根据自己的情况和业务处理能力来处理(就好比说能力不够就不要揽太多活,Consumer性能不够就不会同时处理太多业务)。

在事件模式中,Publisher在处理完业务后,就只管发布事件给Broker。剩下的由Broker和Consumer完成。这样Publisher与Consumer并没有直接通讯,而且Publisher也无需等待响应,即可以降低耦合、减少级联失败的情况,又能提高性能、减少资源浪费。Broker在这一模式中,就像是一个数据总线,所有的服务要接收数据和发送数据都发到这个总线上;这个总线就像协议一样,让服务间的通讯变得标准和可控。

在实际应用中,发布者与订阅者是相对的。也就是说,从整个系统来看,发布者可以是订阅者,订阅者也可以是发布者;从具体的业务逻辑线上看,才有某个服务是另外某个服务的发布者,某个服务是另外某个服务的订阅者。

使用事件模式的异步通讯的好处:

  • 吞吐量提升:发布者无需等待订阅者处理完成,响应更快速。
  • 故障隔离:服务没有直接调用,不存在级联失败问题。
  • 提高资源利用:调用间没有阻塞,不会造成无效的资源占用。
  • 耦合度极低:由Borker做代理,每个服务都可以灵活插拔,可替换。
  • 流量削峰:不管发布事件的流量波动多大,都由Broker接收,订阅者可以按照自己的速度去处理事件。

虽然异步通讯好处多,但是也不是没有缺点:

  • 架构复杂,业务没有明显的流程线,不易于管理。
  • 需要依赖于Broker的可靠、安全、性能(Broker挂了,就没人给订阅者发消息了)。

MQ 技术

MQ(Message Queue,消息队列),就是存放消息的队列,是实现事件驱动架构中的Broker的一种方法。

比较常见的几种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。