构建微服务:微服务体系结构中的进程间通信

 

 

构建微服务:微服务体系结构中的进程间通信

 

Tags

克里斯·理查森(ChrisRichardson)。

编辑-这个由七部分组成的系列文章现已完成:

 

导言

  1. 微服务导论
  2. 构建微服务:使用API网关
  3. 构建微服务:微服务体系结构中的进程间通信
  4. 微服务体系结构中的服务发现
  5. 事件驱动的微服务数据管理
  6. 选择Microservices部署策略
  7. 将Monolith重构为MicroServices

在单块应用程序中,组件通过语言级方法或函数调用相互调用.相反,基于微服务的应用程序是运行在多台机器上的分布式系统.每个服务实例通常都是一个进程。因此,如下图所示,服务必须使用进程间通信(IPC)机制进行交互。


In a microservices application, the services need an inter-process communication (IPC) mechanism (whereas modules in a monolith can call routines)

稍后,我们将讨论特定的IPC技术,但首先让我们探讨各种设计问题。

交互风格

在为服务选择IPC机制时,首先考虑服务是如何交互的是很有用的。有多种客户端⇔服务交互样式。它们可以按两个维度分类。第一个维度是相互作用是一对一还是一对多:

  • 每个客户端请求都由一个服务实例处理。
  • 每个请求由多个服务实例处理。

第二个维度是交互是同步的还是异步的:

  • 同步-客户端期望得到来自服务的及时响应,甚至可能在等待时阻塞。
  • 异步-客户端在等待响应时不阻塞,并且响应(如果有的话)不一定立即发送。

下表显示了各种交互样式。

 一对一一对多
同步请求/答复 — 
异步通知发布/订阅
请求/异步响应发布/异步响应

有以下几种一对一的交互:

  • 请求/响应-客户端向服务发出请求并等待响应。客户希望响应能够及时到达。在基于线程的应用程序中,发出请求的线程甚至可能在等待时阻塞.
  • 通知(a.k.a.)(单向请求)-客户端向服务发送请求,但不期望或发送答复。
  • 请求/异步响应-客户端向服务发送请求,服务异步应答。客户端在等待时不阻塞,设计时假定响应可能在一段时间内不会到达。

有以下几种一对多的交互:

  • 发布/订阅-客户端发布通知消息,该消息由零或多个感兴趣的服务使用。
  • 发布/异步响应-客户端发布请求消息,然后等待一定的时间来响应感兴趣的服务。

每个服务通常使用这些交互样式的组合。对于某些服务,一个IPC机制就足够了。其他服务可能需要使用IPC机制的组合。下图显示了在用户请求旅行时,打车应用程序中的服务如何进行交互。


A microservices-based taxi-hailing app can use a variety of communication methods: notification, request-response, publish-subscribe

服务使用通知、请求/响应和发布/订阅的组合。例如,乘客的智能手机向旅行管理服务发送通知,请求收件。旅行管理服务通过使用请求/响应来调用乘客服务来验证乘客的帐户是否处于活动状态。然后,Trip Management服务创建Trip,并使用发布/订阅通知其他服务,包括Dispatcher,Dispatcher定位可用的驱动程序。

现在我们已经了解了交互风格,让我们看看如何定义API。

定义API

服务的API是服务与其客户端之间的契约。不管您选择什么IPC机制,使用某种接口定义语言(IDL)精确定义服务的API是很重要的。使用API-第一方法定义服务。您可以通过编写接口定义并与客户端开发人员一起审查服务来开始服务的开发。只有在对API定义进行迭代之后,才能实现该服务。提前完成此设计会增加您构建满足其客户需求的服务的机会。

正如您在本文后面将看到的那样,API定义的性质取决于您使用的IPC机制。如果使用消息传递,则API由消息通道和消息类型组成。如果使用HTTP,则API由URL以及请求和响应格式组成。稍后,我们将更详细地描述一些IDL。

进化API

服务的API总是随着时间的推移而变化。在单块应用程序中,更改API和更新所有调用方通常很简单。在基于微服务的应用程序中,即使API的所有使用者都是同一应用程序中的其他服务,也要困难得多。您通常不能强迫所有客户端与服务同步升级。另外,你很可能递增地部署服务的新版本这样,旧版本和新版本的服务将同时运行。必须制定一项处理这些问题的战略。

如何处理API更改取决于更改的大小。有些更改很小,并且向后兼容上一个版本。例如,您可以向请求或响应添加属性。设计客户端和服务以便他们观察鲁棒性原理. Clients that use an older API should continue to work with the new version of the service. The service provides default values for the missing request attributes and the clients ignore any extra response attributes. It is important to use an IPC mechanism and a messaging format that enable you to easily evolve your APIs..

但是,有时您必须对API进行重大的、不兼容的更改。由于无法强制客户端立即升级,服务必须在一段时间内支持API的旧版本。如果使用基于HTTP的机制(如REST),一种方法是将版本号嵌入URL中。每个服务实例可以同时处理多个版本。或者,您可以部署不同的实例,每个实例处理特定的版本。

局部故障处理

上一篇关于API网关的文章,在分布式系统中,始终存在部分故障的风险。由于客户端和服务是独立的进程,服务可能无法及时响应客户端的请求。服务可能因故障或维护而中断。或者服务可能被重载,并且对请求的响应非常慢。

例如,考虑产品细节场景从那篇文章。让我们假设推荐服务没有响应。客户端的简单实现可能会无限期地阻止等待响应。这不仅会导致糟糕的用户体验,而且在许多应用程序中,它会消耗宝贵的资源,比如线程。最后,运行时将耗尽线程,并变得没有响应性,如下图所示。


A microservices app must be designed to handle partial failures, or else the runtime might run out of threads when clients block waiting for an unresponsive service

为了防止这个问题,您必须设计您的服务来处理部分故障。

一个很好的方法是跟随Netflix。处理部分失败的战略包括:

  • 网络超时-永远不要无限期地阻塞,并且总是在等待响应时使用超时。使用超时确保资源不会无限期地被占用。
  • 限制未执行请求的数量-对客户端可以使用特定服务的未执行请求的数量设置上限。如果已经达到了限制,那么提出额外的请求可能是毫无意义的,而这些尝试需要立即失败。
  • 断路器型式-跟踪成功和失败请求的数量。如果错误率超过所配置的阈值,则触发断路器,使进一步的尝试立即失败。如果大量请求失败,这意味着服务不可用,发送请求没有意义。超时一段时间后,客户端应该再试一次,如果成功,则关闭断路器。
  • 提供回退-当请求失败时执行回退逻辑。例如,返回缓存的数据或默认值(如空建议集)。

Netflix hystrix是一个实现这些模式和其他模式的开源库。如果您正在使用JVM,那么一定要考虑使用hystrix。而且,如果在非JVM环境中运行,则应该使用等效的库。

IPC技术

有许多不同的IPC技术可供选择。服务可以使用基于同步请求/响应的通信机制,如基于HTTP的REST或Th残留物。或者,他们可以使用异步的、基于消息的通信机制,例如AMQP或STOMP.还有各种不同的消息格式。服务可以使用人类可读的、基于文本的格式,如JSON或XML。或者,它们可以使用二进制格式(更有效),例如Avro或Protocol缓冲区。稍后我们将讨论同步IPC机制,但首先让我们讨论异步IPC机制。

异步的、基于消息的通信

当使用消息传递时,进程通过异步交换消息进行通信。客户端通过发送消息向服务发出请求。如果期望服务回复,则通过向客户端发送一条单独的消息来实现。由于通信是异步的,所以客户端不会阻止等待回复。相反,客户端是在假定不会立即收到答复的情况下编写的。

讯息由标题(元数据,如发件人)和消息体组成。消息交换通道。任何数量的生产者都可以向信道发送消息。类似地,任何数量的使用者都可以从一个通道接收消息。有两种渠道,点对点发布-订阅。点对点通道将消息传递给正在从频道读取的用户之一。服务使用点对点通道进行前面描述的一对一交互样式。发布订阅通道将每条消息传递给所有附加的使用者。服务使用上述一对多交互样式的发布-订阅通道.

下图显示了打车应用程序如何使用发布-订阅通道。


Microservices in taxi-hailing application use publish-subscribe channels for communication between dispatcher and other services

TripManagement服务通过将创建的旅行消息写入发布-订阅通道通知感兴趣的服务(如调度程序)。调度程序找到可用的驱动程序,并通过将驱动程序建议的消息写入发布订阅通道通知其他服务。

有许多消息传递系统可供选择。您应该选择一种支持多种编程语言的语言。一些消息传递系统支持标准协议,如AMQP和STOMP。其他消息传递系统有专有的但有文档记录的协议。有大量的开放源代码消息传递系统可供选择,包括兔MQ阿帕奇卡夫卡ApacheActiveMQ,和NSQ。在高级别上,它们都支持某种形式的消息和通道。他们都努力做到可靠、高性能和可伸缩。但是,每个代理的消息传递模型的细节都有显著差异。

使用消息传递有许多优点:

  • 将客户端与服务分离-客户端只通过向适当的通道发送消息来发出请求。客户端完全不知道服务实例。它不需要使用发现机制来确定服务实例的位置。
  • 消息缓冲-使用同步请求/响应协议(如HTTP),客户端和服务都必须在交换期间可用。相反,MessageBroker将写入通道的消息排队,直到使用者能够处理它们。这意味着,例如,在线商店可以接受客户的订单,即使订单履行系统是缓慢的或不可用的。订单消息只需排队。
  • 灵活的客户服务交互-消息传递支持前面描述的所有交互样式。
  • 基于RPC的显式进程间通信机制试图使远程服务的调用看起来与调用本地服务相同。然而,由于物理定律和部分失效的可能性,它们实际上是完全不同的。消息传递使这些差异非常明显,因此开发人员不会被诱骗到错误的安全感中。

然而,使用消息传递有一些缺点:

  • 额外的操作复杂性-消息传递系统是另一个必须安装、配置和操作的系统组件。消息代理必须是高度可用的,否则系统的可靠性就会受到影响。
  • 实现基于请求/响应的交互的复杂性-请求/响应风格的交互需要一些工作来实现。每个请求消息必须包含一个应答信道标识符和一个相关标识符。服务将包含相关ID的响应消息写入应答通道。客户端使用相关ID将响应与请求匹配。通常更容易使用直接支持请求/响应的IPC机制。

现在我们已经了解了如何使用基于消息传递的IPC,让我们检查一下基于请求/响应的IPC。

同步、请求/响应IPC

当使用基于同步、请求/响应的IPC机制时,客户端向服务发送请求。服务处理请求并发回响应。在许多客户端中,发出请求的线程在等待响应时阻塞。其他客户端可能使用异步、事件驱动的客户端代码,这些代码可能是由期货或Rx可观察对象封装的。但是,与使用消息传递时不同的是,客户端假定响应将以及时的方式到达。有许多协议可供选择。两种流行的协议是REST和Thriver。让我们先来看看休息。

休息

现在,在安息风格。REST是一种(几乎总是)使用HTTP的IPC机制。REST中的一个关键概念是资源,它通常表示业务对象(如客户或产品)或业务对象集合。REST使用HTTP谓词来操作使用URL引用的资源。例如,GETRequest返回资源的表示形式,它可能以XML文档或JSON对象的形式出现。一个POST请求创建一个新资源,并创建一个PUT请求更新资源。引用RoyFielding的话,他是REST的创造者:

REST提供了一组体系结构约束,当作为一个整体应用时,这些约束强调组件交互的可伸缩性、接口的通用性、组件的独立部署以及中间组件,以减少交互延迟、增强安全性和封装遗留系统。“

-菲尔丁体系结构风格与基于网络的软件体系结构设计

下图显示了打车应用程序使用REST的一种方式。


In microservices-based taxi-hailing app, passenger smartphone sends POST request, which trip management microservice converts to GET request to passenger-verification microservice

乘客的智能手机请求一次旅行POST/trips旅行管理服务的资源。此服务通过发送GET要求乘客管理部门提供有关旅客的信息。在验证乘客被授权创建旅行后,旅行管理服务将创建该旅行并返回201对智能手机的回应。

许多开发人员声称他们基于HTTP的API是RESTful的。然而,正如Fielding在本文中所描述的博客帖子并不是所有的人都是。伦纳德理查森(没有关系)定义了一个非常有用的REST成熟度模型这包括以下几个级别。

  • 级别0-级别0 API的客户端通过生成HTTP调用服务POST对其唯一URL端点的请求。每个请求指定要执行的操作、操作的目标(例如业务对象)和任何参数。
  • 级别1-一级API支持资源的概念。若要对资源执行操作,客户端将生成POST指定要执行的操作和任何参数的请求。
  • 级别2-二级API使用HTTP谓词执行操作:GET为了找回,POST创造,和PUT更新。请求查询参数和正文(如果有的话)指定操作的参数。这使服务能够利用web基础结构,例如缓存GET请求。
  • 第三级-第3级API的设计基于被命名为超级文本作为应用程序状态引擎(Hypertext As The Engine Of Application State)的原理。的基本思想是,由GET请求包含对该资源执行允许操作的链接。例如,客户端可以使用响应于GET请求检索订单。HATEAmerican的好处包括不再需要硬连接URL到客户端代码。另一个好处是,由于资源的表示包含允许操作的链接,因此客户端不必猜测在当前状态下可以对资源执行哪些操作。

使用基于HTTP的协议有许多好处:

  • http是简单而熟悉的。
  • 可以在浏览器中使用扩展名测试HTTPAPI,如邮递员或从命令行使用curl(假设使用了JSON或其他文本格式)。
  • 它直接支持请求/响应方式的通信。
  • 当然,http对防火墙是友好的。
  • 它不需要中间代理,这简化了系统的体系结构。

使用HTTP有一些缺点:

  • 它只直接支持交互的请求/响应风格。您可以使用HTTP进行通知,但服务器必须始终发送HTTP响应。
  • 因为客户端和服务直接通信(没有中间层来缓冲消息),所以它们必须在交换期间运行。
  • 客户端必须知道每个服务实例的位置(即URL)。如上一篇关于API网关的文章,这是现代应用程序中一个重要的问题。客户端必须使用服务发现机制来定位服务实例。

开发人员社区最近重新发现了RESTfulAPI的接口定义语言的价值。有几种选择,包括拉姆尔昂首阔步。有些IDL(如Swagger)允许您定义请求和响应消息的格式。其他如Raml等则要求您使用单独的规范,如JSON模式。除了描述API之外,IDL通常还拥有从接口定义生成客户端存根和服务器框架的工具。

节俭

阿帕奇是一个有趣的替代休息。这是一个跨语言的写作框架。RPC clients and servers. Thrift provides a C‑style IDL for defining your APIs. You use the Thrift compiler to generate client‑side stubs and server‑side skeletons. The compiler generates code for a variety of languages including C++, Java, Python, PHP, Ruby, Erlang, and Node.js.

Th裂缝接口由一个或多个服务组成。服务定义类似于Java接口。它是强类型方法的集合。节约方法可以返回(可能为空)值,也可以定义为单向。返回值的方法实现交互的请求/响应样式。客户端等待响应并可能引发异常。单向方法对应于交互的通知样式。服务器不发送响应。

节俭支持各种消息格式:json、二进制和紧凑二进制。二进制比JSON更高效,因为它的解码速度更快。而且,顾名思义,紧凑二进制是一种节省空间的格式。当然,JSON对人和浏览器都很友好。节俭还为您提供了传输协议的选择,包括原始TCP和HTTP。原始TCP可能比HTTP更有效。然而,HTTP是防火墙,浏览器,和人友好。

消息格式

现在我们已经看过了HTTP和Thriver,让我们来看看消息格式的问题。如果您正在使用消息传递系统或REST,则可以选择您的消息格式。其他IPC机制,如Thriver,可能只支持少量的消息格式,可能只支持一种消息格式。在任何一种情况下,使用跨语言消息格式都很重要。即使您现在正在用一种语言编写您的微服务,将来也很可能使用其他语言。

消息格式主要有两种:文本格式和二进制格式。基于文本格式的示例包括JSON和XML。这些格式的一个优点是,它们不仅是人类可读的,而且是自我描述的。在JSON中,对象的属性由名称-值对的集合表示。类似地,在XML中,属性由命名元素和值表示。这使得消息的使用者能够选择它感兴趣的值,而忽略其余的值。因此,对消息格式的微小更改可以很容易地向后兼容。

XML文档的结构由XML模式。随着时间的推移,开发人员社区已经意识到JSON也需要类似的机制。一种选择是使用JSON模式,或者是独立的,或者是IDL的一部分,比如Swagger。

使用基于文本的消息格式的一个缺点是,消息往往是冗长的,特别是XML。因为消息是自描述的,所以每条消息除了包含它们的值外,还包含属性的名称。另一个缺点是解析文本的开销。因此,您可能需要考虑使用二进制格式。

有几种二进制格式可供选择。如果您使用的是ThraceRPC,则可以使用二进制的。如果选择消息格式,流行选项包括协议缓冲器阿帕奇·阿夫罗。这两种格式都提供了用于定义消息结构的类型化IDL。然而,一个不同之处是,协议缓冲区使用标记字段,而Avro使用者需要知道模式才能解释消息。因此,使用协议缓冲区比使用Avro更容易使用API。这,这个博客帖子这是一个非常好的比较,它可以比较Thriver、Protocol Buffers和Avro。

摘要

微服务必须使用进程间通信机制进行通信.在设计服务的通信方式时,您需要考虑各种问题:服务如何交互,如何为每个服务指定API,如何发展API,以及如何处理部分故障。微服务可以使用两种IPC机制:异步消息传递机制和同步请求/响应机制。在本系列的下一篇文章中,我们将研究微服务体系结构中的服务发现问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值