
嗨,habrozhiteli! 我们最近将
克里斯·理查森 (
Chris Richardson)的一本书移交给了印刷厂,目的是教授使用微服务架构成功进行应用程序开发的知识。 该书不仅讨论了微服务的优点,还讨论了其缺点。 您将学习在什么情况下应用它们是有意义的,以及何时最好考虑整体方法。
这本书着重于建筑和设计。 它适用于负责编写和交付软件的任何人员,包括开发人员,架构师,技术总监和开发部门负责人。
以下是《使用异步消息》一书的摘录
使用异步消息传递来提高可用性
如您所见,各种IPC机制会促使您做出各种折衷。 其中之一与IPC如何影响可访问性有关。 在本节中,您将学习到作为请求处理一部分的与其他服务的同步交互会降低应用程序的可用性。 因此,在设计服务时,应尽可能使用异步消息传递。
首先,让我们看看同步交互会产生什么问题以及它如何影响可访问性。
3.4.1。 同步交互会降低可用性
REST是一种非常流行的IPC引擎。 您可能会想将其用于服务间通信。 但是REST的问题在于它是一个同步协议:HTTP客户端必须等待,直到服务返回响应。 每次服务通过同步协议相互通信时,都会降低应用程序的可用性。
要了解为什么会发生这种情况,请考虑图11中所示的情况。 3.15。 订单服务具有用于创建订单的REST API。 为了检查订单,他转向了Consumer and Restaurant服务,该服务也具有REST API。
创建订单包含此步骤序列。
- 客户端向订单服务发出HTTP POST /订单请求。
- 订单服务通过向消费者服务发出HTTP GET /消费者/ id请求来检索客户信息。
- 订单服务通过对餐厅服务执行HTTP GET / restaurant / id请求来检索餐厅信息。
- 接受订单使用有关客户和餐厅的信息检查请求。
- 接单创建订单。
- 接受订单将HTTP响应发送到客户端。
由于这些服务使用HTTP,因此FTGO必须可以访问所有服务以处理CreateOrder请求。 如果至少一项服务不可用,它将无法创建订单。 从数学的角度来看,系统操作的可用性是其中所涉及服务的可用性的产物。 如果Order服务及其调用的两个服务的可用性为99.5%,则它们的总体可用性将为99.5%3 = 98.5%,这要低得多。 参与该请求的每个后续服务使该操作不可访问。
此问题并非基于REST的交互所独有。 每当服务需要从其他服务接收响应以响应客户端时,可用性就会降低。 即使在异步消息之上转换为请求/响应交互样式也无济于事。 例如,如果订购服务通过代理将消息发送到消费者服务并开始等待响应,则其可用性将下降。
如果要最大化可访问性,请最小化同步交互的数量。 让我们来看看如何做。
3.4.2。 摆脱同步互动
处理同步请求时,有几种方法可以减少与其他服务的同步交互。 首先,为完全避免此问题,可以为所有服务提供专用的异步API。 但这并不总是可能的。 例如,公共API通常遵守REST标准。 因此,某些服务需要具有同步API。
幸运的是,要处理同步请求,不必自己执行它们。 让我们谈谈这些选项。
使用异步交互样式理想情况下,所有交互都应以本章前面介绍的异步方式进行。 例如,假设FTGO应用程序客户端使用异步请求/异步响应交互样式来创建订单。 要创建订单,他将请求消息发送到订单服务。 然后,该服务与其他服务异步交换消息,并最终向客户端返回响应(图3.16)。
客户端和服务异步通信,通过通道发送消息。 此交互中的任何参与者都不会被阻止等待响应。
这样的体系结构将非常健壮,因为代理会缓冲消息,直到可能消耗消息为止。 但问题在于,服务通常具有使用REST等同步协议的外部API,因此必须立即响应请求。
如果服务具有同步API,则可以通过数据复制来改善可访问性。 让我们看看它是如何工作的。
资料复制在查询处理期间最小化同步交互的一种方法是复制数据。 该服务存储处理请求所需的数据的副本(副本)。 为了使副本保持最新状态,它预订此数据所属的服务所发布的事件。 例如,订购服务可以存储属于消费者和饭店服务的数据副本。 这样,他就可以处理创建订单的请求,而无需借助这些服务。 这样的架构在图1中示出。 3.17。
消费者和餐厅服务在数据更改时都会发布事件。 订单服务订阅这些事件并更新其副本。
在某些情况下,数据复制是一个很好的解决方案。 例如,第5章介绍了Order服务如何复制Restaurant服务数据以能够检查菜单项。 这种方法的缺点之一是有时需要复制大量数据,这效率很低。 例如,如果我们有很多客户,则存储属于消费者服务的数据副本可能是不切实际的。 复制的另一个缺点在于,它不能解决更新属于其他服务的数据的问题。
为了解决此问题,服务可以延迟与其他服务的交互,直到它响应其客户端为止。 这将进一步讨论。
返回响应后结束处理消除查询处理期间的同步交互的另一种方法是以以下步骤的形式执行此处理。
- 该服务仅在本地可用数据的帮助下检查请求。
- 它更新其数据库,包括将消息添加到OUTBOX表。
- 将响应返回给其客户端。
在处理请求期间,该服务不会同步访问任何其他服务。 相反,他向他们发送异步消息。 这种方法提供了较差的服务连接。 正如您将在下一章中看到的那样,该过程通常是作为叙述实现的。
想象一下,订购服务以这种方式工作。 他创建状态为PENDING的订单,然后通过与其他服务交换异步消息进行检查。 在图。 图3.18显示了调用createOrder()操作时发生的情况。 事件链看起来像这样。
- 订单服务创建状态为PENDING的订单。
- 订单服务向其客户返回带有订单ID的响应。
- 订单服务将ValidateConsumerInfo消息发送到使用者服务。
- 订单服务将ValidateOrderDetails消息发送到餐厅服务。
- 消费者服务接收ValidateConsumerInfo消息,检查客户是否可以下订单,然后将ConsumerValidated消息发送到订单服务。
- 饭店服务接收ValidateOrderDetails消息,检查菜单项的正确性以及饭店将订单传递到给定地址的能力,然后将OrderDetailsValidated消息发送到订购服务。
- 订单服务接收ConsumerValidated和OrderDetailsValidated消息,并将订单状态更改为VALIDATED。
依此类推...
订单服务可以按任何顺序接收ConsumerValidated和OrderDetailsValidated消息。 要知道他首先收到的是哪个,他更改了订单状态。 如果第一条消息是ConsumerValidated,则订单状态更改为CONSUMER_VALIDATED,如果OrderDetailsValidated更改为ORDER_DETAILS_VALIDATED。 收到第二条消息后,订单服务将订单状态设置为VALIDATED。
检查订单后,订单服务将执行其余步骤以创建订单,我们将在下一章中讨论。 这种方法的很大一部分是,即使无法使用“消费者”服务,“订单”服务也可以创建订单并响应客户。 消费者服务迟早将恢复并处理所有未决消息,这将完成订单验证。
在请求完全处理之前返回响应的缺点是使客户端更加复杂。 例如,当订单服务返回响应时,它将为刚刚创建的订单状态提供最小的保证。 即使在检查订单和授权客户的银行卡之前,他也会立即回答。 因此,为了找出是否已成功创建订单,客户端必须定期请求信息,或者订单服务必须向他发送通知消息。 尽管这种方法很复杂,但是在很多情况下还是值得推荐,尤其是因为它考虑了分布式事务管理的问题,我们将在第4章中进行讨论。在第4和第5章中,我将以Order服务为例来演示这种技术。
总结
- 微服务架构是分布式的,因此进程间通信在其中起着关键作用。
- 必须仔细仔细地研究API服务的开发。 进行向后兼容的更改最容易,因为它们不会影响客户的工作方式。 在对服务API进行重大更改时,通常必须维护旧版本和新版本,直到客户端更新为止。
- IPC技术很多,每种都有其优点和缺点。 在设计阶段的关键决定是在同步远程过程调用和异步消息之间进行选择。 基于远程过程的调用,最容易使用的是诸如REST之类的同步协议。 但是理想情况下,为了增加可访问性,服务应该使用异步消息传递进行通信。
- 为了防止类似雪崩般的故障累积在系统中,使用同步协议的客户端必须能够处理部分故障-事实是被叫服务要么不可用,要么表现出高延迟。 特别是在执行请求时,有必要计算等待时间,限制逾期请求的数量,并应用“ Fuse”模板,以避免调用错误服务。
- 使用同步协议的体系结构必须包括发现机制,以便客户端可以确定服务实例的网络位置。 最简单的方法是着重于部署平台提供的发现机制:“服务器端发现”和“第三方注册”模板。 另一种方法是在应用程序级别上实现服务发现:客户端发现和自我注册模板。 此方法需要更多的精力,但适用于服务在多个部署平台上运行的情况。
- 消息和通道模型封装了消息传递系统的实现细节,并且在设计这种类型的体系结构时成为不错的选择。 稍后,您可以将体系结构绑定到通常使用代理的特定消息传递基础结构。
- 消息传递中的主要困难是数据库的发布和更新。 一个好的解决方案是使用事件发布模板:消息在事务的最开始就被写入数据库。 然后,一个单独的过程使用询问发布者或事务日志跟踪模板从数据库中检索消息,并将其传递给代理。
»这本书的更多信息可以
在出版商的网站上找到»
目录»
摘录对于Khabrozhiteley,可通过优惠券在预购书上享受30%的折扣-Microservices