微服务架构是一种既定模式,用于构建由松散耦合模块组成的复杂系统。它是过去几年中最受关注的软件架构趋势之一。将一个大型的、相互依赖的系统分解成许多小的、轻量级的模块,这似乎是一个非常简单的想法,这些模块可以使软件管理更容易。
这里有一个要点:在将整体应用程序分解为小模块之后,应该如何以有意义的方式将它们连接在一起?不幸的是,这个问题没有单一的正确答案,但通常情况下,有几种方法取决于应用程序和个别用例。
微服务中使用的两种常见协议是使用资源 API 的 HTTP 请求/响应和跨多个微服务通信更新时的轻量级异步消息传递。让我们探索这些协议。
通讯类型
微服务可以通过多种不同的通信模式进行通信,每种模式都针对不同的用例。这些类型的通信主要可以分为两个维度。第一个维度定义通信协议是同步的还是异步的:
同步与异步通信第二个维度定义了通信是有一个接收者还是多个接收者:
微服务之间最常见的通信类型是在调用 REST API 时使用同步协议(如 HTTP/HTTPS)的单接收器通信。微服务通常使用消息协议在微服务之间进行异步通信。这种异步通信可能涉及单个接收器或多个接收器,具体取决于应用程序的需要。
表征状态转移
表述性状态传输 (REST) 是一种流行的请求和响应通信架构风格,它可以作为同步通信类型的一个很好的例子。这是基于 HTTP 协议,包含 GET、POST、PUT、DELETE 等动词。在这种通信模式中,调用者等待服务器的响应。
图 1:基于 REST API 的通信
REST 是服务间通信最常用的架构风格,但在涉及微服务架构时,严重依赖这种类型的通信会产生一些负面影响:
- 多次往返(延迟) ——客户端通常需要执行多次到服务器的行程以获取客户端所需的所有数据。每个端点指定固定数量的数据,并且在许多情况下,该数据只是客户端填充其页面所需的数据的一个子集。
- 阻塞——调用 REST API 时,客户端被阻塞并等待服务器响应。如果应用程序线程正在处理其他并发请求,这可能会损害应用程序性能。
- 紧耦合——客户端和服务器需要相互了解。随着时间的推移,它会增加复杂性并降低可移植性。
讯息
消息在遵循异步协议的微服务架构中被广泛使用。在此模式中,服务发送消息而不等待响应,并且一个或多个服务异步处理消息。异步消息传递提供了许多好处,但也带来了幂等性、消息排序、毒消息处理和消息代理的复杂性等挑战,这些消息代理必须具有高可用性。
重要的是要注意异步 I/O 和异步协议之间的区别。异步 I/O意味着调用线程在执行 I/O 操作时不会被阻塞。这是软件设计方面的一个实现细节。异步协议意味着发送方不等待响应。
图 2:基于消息的通信
异步消息传递与同步消息传递相比有一些优势:
- 松耦合——消息生产者不需要知道消费者。
- 多个订阅者——使用发布者/订阅者 (pub/sub) 模型,多个消费者可以订阅接收事件。
- 弹性或故障隔离——如果消费者发生故障,生产者仍然可以发送消息。当消费者从失败中恢复时,消息将被拾取。这在微服务架构中特别有用,因为每个微服务都有自己的生命周期。
- 非阻塞——生产者和消费者可以按照自己的节奏发送和处理消息。
尽管异步消息传递有很多优点,但它也有一些折衷:
- 与消息传递基础设施的紧密耦合——使用特定的供应商/消息传递基础设施可能会导致与该基础设施的紧密耦合。以后可能很难切换到另一个供应商/消息基础设施。
- 复杂性——处理异步消息可能不像设计 REST API 那样容易。必须通过去重或使操作幂等来处理重复的消息。使用异步消息传递很难实现请求-响应语义。要发送响应,需要另一个队列以及关联请求和响应消息的方法。调试也很困难,因为很难确定服务 A 中的哪个请求导致了服务 B 中的错误行为。
异步消息传递已经成熟为多种消息传递模式。这些模式适用于分布式系统的多个部分必须以可靠和可扩展的方式相互通信的场景。让我们来看看其中的一些模式。
发布/订阅模式
发布/订阅模式意味着发布者将消息发送到消息代理上的通道。一个或多个订阅者订阅频道并以异步方式从频道接收消息。当微服务需要向大量消费者广播信息时,此模式很有用。
图 3:发布/订阅模式
发布/订阅模式具有以下优点:
- 它解耦了需要通信的发布者和订阅者。发布者和订阅者可以独立管理,即使一个或多个订阅者离线也可以管理消息。
- 它增加了可扩展性并提高了发布者的响应能力。发布者可以快速将消息发布到输入通道,然后返回其核心处理职责。消息传递基础设施负责确保将消息传递给感兴趣的订阅者。
- 它为微服务提供 关注点分离。每个微服务都可以专注于其核心职责,而消息代理处理将消息可靠地路由到多个订阅者所需的一切。
使用这种模式有一些缺点:
- 发布/订阅模式在发布者传递给订阅者的消息中引入了高度语义耦合。数据结构一旦建立,通常很难改变。要更改消息结构,必须更改所有订阅者以接受更改后的格式。如果订户是外部的,这可能很困难或不可能。
- 发布/订阅模式的另一个缺点是很难衡量订阅者的健康状况。发布者不知道收听消息的系统的健康状况。
- 随着发布/订阅系统的扩展,代理通常成为消息流的瓶颈。负载激增会减慢发布/订阅系统的速度,订阅者的响应时间可能会出现峰值。
基于队列的模式
在基于队列的模式中,发送方将消息发布到包含接收方所需数据的队列。队列充当缓冲区,存储消息直到它被接收者检索。接收者从队列中检索消息并按照自己的节奏处理它们。此模式对于使用容易过载的服务的任何应用程序都很有用。
图 4:基于队列的模式
基于队列的模式有以下优点:
- 它可以帮助最大限度地提高可扩展性,因为队列数量和服务数量都可以扩展以满足需求。
- 它可以帮助最大限度地提高可用性。生产者或消费者中出现的延迟不会对服务产生直接或直接的影响,即使消费者不可用或处理消息的负载很重,服务也可以继续将消息发布到队列中。
使用这种模式有一些缺点:
- 当消费者从队列中收到一条消息时,该消息在队列中不再可用。如果消费者未能处理消息,消息将丢失并且可能需要在消费者中回滚。
- 消息队列不是开箱即用的。我们需要创建、配置和监控它们。当系统扩展时,它可能会导致操作复杂性。
简化消息传递基础架构的关键
异步通信通常通过消息代理进行管理。在为异步通信选择正确的消息传递基础设施时,需要考虑一些因素:
- 可扩展性——消息代理负载激增时自动扩展的能力
- 数据持久性——在重启/失败的情况下恢复消息的能力
- 消费者能力——经纪人是否可以管理一对一和/或一对多消费者
- 监控——是否具备监控能力
- 推送和拉取队列——通过消息队列处理推送和拉取传递的能力
- 安全性——对消息队列和主题进行适当的身份验证和授权
- 自动故障转移——能够在一个代理发生故障时自动连接到故障转移代理而不影响发布者/消费者
结论
微服务越来越成为设计可扩展和弹性系统的实际方法。微服务之间的所有通信都没有单一的方法。RESTful API 提供请求-响应模型以在服务之间进行通信,而异步消息传递则在不同服务之间提供更具可扩展性的生产者-消费者关系。尽管微服务可以通过消息传递和 REST API 相互通信,但消息传递架构是提高敏捷性和快速移动的理想选择。它们常见于使用微服务的现代应用程序或任何具有解耦组件的应用程序中。
在为您的微服务选择合适的通信方式时,请务必将消费者的需求与一种或多种通信类型相匹配,从而为您的服务提供强大的接口。