服务之间的调用

相比较于单体应用,分布式应用每个服务都在不同的进程,甚至部署在不同的服务器上,所以不能采用单体应用时方法的直接调用,需要采用IPC、RPC或消息服务来进行交互。

交互方式

根据客户端和服务端的数量可以分为:

  • 一对一:一个客户端对应一个服务端
  • 一对多:一个客户端对应多个服务端
    根据是否阻塞进程运行可以分为:
  • 同步:阻塞
  • 异步:不阻塞
    下表展示了各种交互方式
  一对一 一对多
同步 请求/响应 -
异步 通知 发布/订阅
异步 请求/异步响应 发布/异步响应
  • 客户端/服务器端
    一般来说,如果A调用B的服务,B进行具体的数据处理,那么A为客户端,B为服务端。
  • 服务消费方/服务提供方
    如果A调用B服务,A为服务消费方,B为服务提供方
  • 消息生成者/消息消费者
    A主动发送消息给B,那么A为生产者,B为接收者

定义API

服务 API 是服务与客户端之间的契约。无论您选择何种 IPC 机制,使用接口定义语言(interface definition language,IDL)来严格定义服务 API 都是非常有必要的。

定义 API 的方式取决于您使用何种 IPC 机制。如果您正在使用消息传递,那么 API 是由消息通道和消息类型组成。如果您使用的是 HTTP,那么 API 是由 URL、请求和响应格式组成。

异步、基于消息的通信

当使用消息传递时,进程通过异步交换消息进行通信。客户端通过发送消息向服务发出请求。如果服务需要回复,则通过向客户端发送一条单独的消息来实现。由于通信是异步的,因此客户端不会阻塞等待回复。相反,客户端被假定不会立即收到回复。

一条消息由头部(如发件人之类的元数据)和消息体组成。消息通过通道进行交换。任何数量的生产者都可以向通道发送消息。类似地,任何数量的消费者都可以从通道接收消息。有两种通道类型,分别是点对点(point‑to‑point)与发布订阅(publish‑subscribe)。

  • 点对点
    发送一条消息给一个切确的、正在从通道读取消息的消费者。服务使用点对点通道,就是上述的一对一交互方式。
  • 发布/订阅
    将每条消息传递给所有已订阅的消费者。服务使用发布订阅通道,就是上述的一对多交互方式
    xx
    这个图片是一个例子,TripManager生成了一个旅程,通过消息发布传递到Dispatcher,然后Dispatcher匹配到合适的司机后通过消息发布通知到多个服务,让司机端,客户端,trip端都得到订单生成的消息。

有许多消息系统可供选择,您应该选择一个支持多种编程语言的。

一些消息系统支持标准协议,如 AMQP 和 STOMP。其他消息系统有专有的文档化协议。

有大量的开源消息系统可供选择,包括 RabbitMQ、Apache Kafka、Apache ActiveMQ 和 NSQ。从高层而言,他们都支持某种形式的消息和通道。他们都力求做到可靠、高性能和可扩展。然而,每个代理的消息传递模型细节上都存在着很大差异。

使用消息队列的优点:

  • 客户端和服务端分离
    客户端和服务端。不直接连接,都之和消息服务连接。
  • 流量削峰
    大量的调用不会导致服务瘫痪,无法处理的排队处理。
  • 毫无隐瞒的进程间通信
    基于 RPC 的机制试图使调用远程服务看起来与调用本地服务相同。然而,由于物理因素和局部故障的可能性,他们实际上是完全不同的。消息传递使这些差异变得非常明显,所以开发人员不会被这些虚假的安全感所欺骗。

使用消息队列的缺点:

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

同步的请求/响应 IPC

REST

如今,开发 RESTful 风格的 API 是很流行的。REST 是一种使用了 HTTP (几乎总是)的 IPC 机制。

资源是 REST 中的一个关键概念,它通常表示业务对象,如客户、产品或这些业务对象的集合。REST 使用 HTTP 动词(谓词)来操纵资源,这些资源通过 URL 引用。例如,GET 请求返回一个资源的表述形式,可能是 XML 文档或 JSON 对象形式。POST 请求创建一个新资源,PUT 请求更新一个资源。
示例图
智能手机向TripManagement发送打车请求,TripManagement向用户服务查询用户信息,两方都通过返回码进行确认。

Thrift

Apache Thrift 是 REST 的一个有趣的替代方案。它是一个用于编写跨语言 RPC 客户端和服务器框架。Thrift 提供了一个 C 风格的 IDL 来定义您的 API。您可以使用 Thrift 编译器生成客户端 stub 和服务器端 skeleton。编译器可以生成各种语言的代码,包括 C++、Java、Python、PHP、Ruby、Erlang 和 Node.js。

Thrift 接口由一个或多个服务组成。服务定义类似于一个 Java 接口。它是强类型方法的集合。

Thrift 方法可以返回一个(可能为 void)值,或者如果它们被定义为单向,则不会返回值。返回值方法实现了请求/响应的交互方式,客户端等待响应,并可能会抛出异常。单向方式对应通知交互方式,服务器不发送响应。

Thrift 支持多种消息格式:JSON,二进制和压缩二进制。二进制比 JSON 更有效率,因为其解码速度更快。而且,顾名思义,压缩二进制是一种节省空间的格式。当然,JSON 是可读的和浏览器友好的。Thrift 还为您提供了包括原始 TCP 和 HTTP 在内的传输协议选择。原始 TCP 可能比 HTTP 更有效率。然而,HTTP 是防火墙友好的、浏览器友好的和可读的。

消息格式

如果您使用的是消息系统或 REST,则可以选择自己的消息格式。其他 IPC 机制如 Thrift 可能只支持少量的消息格式,甚至只支持一种。在任一种情况下,使用跨语言的消息格式都很重要了。即使您现在是以单一语言编写您的微服务,您将来也可能会使用到其他语言。

有两种主要的消息格式:文本和二进制。基于文本格式的例子有 JSON 和 XML。这些格式的优点在于,它们不仅是人类可读的,而且是自描述的。在 JSON 中,对象的属性由一组键值对表示。类似地,在 XML 中,属性由命名元素和值表示。这使得消息消费者能够挑选其感兴趣的值并忽略其余的值。因此,稍微修改消息格式就可以轻松地向后兼容。

XML 文档的结构由 XML 模式(schema)定义。随着时间的推移,开发人员社区已经意识到 JSON 也需要一个类似的机制。一个选择是使用 JSON Schema,无论独立或作为 IDL 的一部分,如 Swagger。

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

有几种二进制格式可供选择。如果您使用的是 Thrift RPC,您可以使用 Thrift 的二进制格式。如果你可以选择消息格式,比较流行的有 Protocol Buffers 和 Apache Avro。这两种格式都提供了一种类型化的 IDL 用于定义消息结构。然而,一个区别是 Protocol Buffers 使用标记字段,而 Avro 消费者需要知道模式才能解释消息。因此,Protocol Buffers 的 API 演化比 Avro 更容易使用。这里有篇博文对 Thrift、Protocol Buffers 和 Avro 作出了极好的比较。

总结

微服务必须使用进程间通信机制进行通信。在设计服务如何进行通信时,您需要考虑各种问题:服务如何交互、如何为每个服务指定 API、如何演变 API 以及如何处理局部故障。微服务可以使用两种 IPC 机制:异步消息传递和同步请求/响应。为了进行通信,一个服务必须能够找到另一个服务。

猜你喜欢

转载自www.cnblogs.com/trembear/p/10882396.html
今日推荐