概览

分布式系统与 CAP 理论这一节我们有提到过,分布式系统是一组通过网络通信来协同对外提供服务的计算机节点。如今炙手可热的微服务架构模式就是分布式系统的实践之一,相比于早起的单体架构,微服务架构通过 DDD 等建模方式将原有的一个系统拆分为多个系统。每个单独的微服务系统具有较高的内聚性,而微服务系统之间通过定义的接口进行通信。微服务间的通信方式,可简单分为同步通信和异步通信,下面我们就一起来了解下这两种通信方式。

同步通信

微服务的同步通信方式类似于操作系统的同步 I/O 调用,他们都有阻塞进/线程的特点,但由于微服务的通信方式是建立于网络通信基础之上的,所以相较于 I/O 调用还需要建立网络连接。熟悉计算机网络的朋友都知道,建立一个网络连接需要四元组,包括通信双方的 ip 地址以及端口号。传统的单体式架构往往会进行固定 ip 的绑定,而微服务架构由于滚动升级,以及伸缩等机制难以为服务实例进行固定 ip 的绑定。因此,这就需要一种能够灵活注册与获取服务实例的网络地址的机制 - 服务发现。

服务发现

服务发现的关键组件是一个服务注册表,它是一个包括实例网络位置信息的一个数据库。在服务实例启动和停止时,服务发现机制会更新服务注册表。当客户端调用服务时,服务发现机制会查询服务注册表以获取可用实例的列表,并将请求路由到其中的一个服务实例。

服务发现共有两种实现方式:

  • 应用层服务发现:服务实例以及客户端直接与服务注册表交互。
  • 平台层服务发现:通过部署基础设施来处理服务发现。

应用层服务发现

在应用层服务发现模式下,服务实例在启动时通过服务注册表提供的 API 进行网络地址自注册,在停止时从注册表中删除注册过的网络地址。客户端在需要调用服务时,则访问通过注册表的查询 API 获取对应服务的一组网络地址,然后将请求根据负载均衡规则将请求发送到某个服务实例上。此外,除了服务实例停止时自行注销网络地址外,应用层服务发现还提供基于运行状况检查的服务注销机制,这类似于 kubernetes 的 liveness probe。当服务注册表发现服务实例不可用时,也会将其网络地址注销。

应用层服务发现可以应对多平台部署问题,但需要服务实例以及客户端具有相应的 SDK。

image.png

图1.应用层服务发现(摘自《微服务设计模式》)

平台层服务发现

平台层服务方式使用第三方注册取代了自注册机制,由部署平台通过注册器实现服务实例的网络地址注册与注销。

部署平台为每个服务提供 DNS 名称、虚拟 IP(VIP)和解析为 VIP 地址的 DNS 名称。客户端向 VIP 和 DNS 名称发出请求,部署平台自动将请求路由到其中一个可用服务实例。因此,服务注册、服务发现和请求路由完全由部署平台处理。

在基于平台层的服务发现机制下,客户端以及服务实例无需关注服务发现的逻辑,并且无需 SDK 的支持,即实现了跨语言通用。但是这也依赖于部署平台需要提供服务发现的功能。

image.png

图2.平台层服务发现(摘自《微服务设计模式》)

断路器模式

同步通信需要通信双方在通信时可用,如果通信过程中被请求方出现不可用的局部故障情况(请求长时间阻塞或者无法建立连接等),且请求方仍然允许大量请求发出,这会消耗大量的资源,甚至会导致微服务雪崩的连锁反应。为避免同步通信过程中因为局部故障而带来更大的风险,我们可以采用断路器模式。

断路器是一个远程过程调用的代理,在连续失败超过指定阈值后的一段时间内,这个代理会立刻拒绝其他调用。

断路器会监控请求方客户端发出请求的成功和失败数量,如果失败的比例超过一定的阈值,就启动断路器,让后续的调用立刻失效。如果大量的请求都已失败告终,则说明被请求服务不可用,这样即使发起更多的调用也是无济于事。在经过一定的时间后,客户端允许请求调用尝试,如果成功,则解除断路器。

目前被广泛采用的同步通信方式包括基于 HTTP 的 REST 以及基于 RPC 的 GRPC 等。他们具有实现方式简单的优点,但也由于同步通信需要处理服务发现以及局部故障等问题,这导致了其可用性较差。

异步通信

异步通信可根据有无消息代理参与分为两类。

无消息代理架构

通过直接向服务发送消息来执行服务请求,如果希望服务实例回复,服务将向客户端发送单独的消息。因为通信是异步的,所以在收发消息时不会阻塞。

有消息代理架构

相较于无消息代理架构,基于消息代理的异步通信方式使用范围更广。微服务之间通过 Kafka 以及 RabbitMQ 等的消息中间件实现一对一或一对多的消息通信。相比于同步通信而言,消息收发双方只需要与消息代理进行交互,由于消息代理一般提供消息缓存的功能,所以一方在收发消息时不需要另一方保持可用。同时,收发双方不需要知道对方的网络地址,这也降低了微服务间的耦合程度。

想了解更多关于消息代理的知识,可以阅读重新认识消息队列

总结

本节我们学习了两种微服务间的通信方式,包括同步通信以及异步通信。同步通信具有实现简单的优点,但因为微服务架构下滚动升级以及伸缩等因素,无法为服务实例固定 IP 地址,所以需要依赖服务发现机制。同时同步通信机制需要通信双方在通信过程中保持可用,若因通信单方不可用导致的局部故障,可能引发微服务雪崩的连锁反应。而基于消息代理的异步通信中,消息收发双方可通过消息代理实现一对一或一对多的通信,消息双发在收发消息时无需另一方同时可用,这大大提高了整体服务的稳定性。

本文参考

微服务设计模式