您的位置:首页 > 博客中心 > 网络系统 >

Chris Richardson微服务翻译:构建微服务之微服务架构的进程通讯

时间:2022-04-03 13:35

Chris Richardson 微服务系列翻译全7篇链接:

  • 构建微服务之微服务架构的进程通讯(本文)

原文链接:


简介

在单体应用中,模块间使用编程语言级别的方法或函数彼此调用。而基于微服务架构的本质是是运行在多台机器上的分布式应用,每个服务都是一个进程。如下图所示,微服务之间必须使用进程间通信(IPC)的机制实现交互:

技术分享

稍后我们将讨论 IPC 技术,先看下设计相关的问题。

交互模式

当为某个服务选择 IPC 机制时,首先要考虑服务间如何交互。client 和 server 端有很多交互的方式,可以按两个维度分类:

第一个维度是一对一还是一对多:

  • 一对一:每个 client 请求只会被一个 server 处理
  • 一对多:每个 client 请求会被多个 server 处理

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

  • 同步模式:client 期望来自 server 的及时响应,甚至可能由于等待而阻塞
  • 异步模式:client 等待响应时不会阻塞,不需要及时响应

下面表格展示了两种方式的不同:

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

 

 

 

 

下面有几种一对一的交互模式:

    上图服务使用了通知、请求/响应、发布/订阅的方式。例如:乘客在移动端向『行程管理服务』发送接送需求的通知;『行程管理服务』使用 请求/响应 模式 调用『乘客服务』来验证乘客账号是否有效;然后『行程管理服务』创建行程并使用 发布/订阅 模式来通知其他服务(定位可用司机的『调度服务』等)。

    我们讨论了交互风格,下面看下如何定义 API。

    为解决此类问题,设计时需要考虑局部故障的问题:

    Netfilix 提供了较好的解决方案:

      行程管理服务向『订阅-发布』频道写入『创建行程』的消息,通知调度服务有新的行程请求。调度服务查找空闲的司机,并通过『发布-订阅』频道写入『推荐司机』的消息,通知其他服务。

      有多种消息系统供我们选择,当然我们尽可能选择支持多种编程语言的。一些消息系统支持 AMQP和 STOMP 这样的标准协议,有的则支持专有的协议。开源的消息系统例如:RabbitMQ、Apacha Kafka、Apache ActiveMQ 和 NSQ。统一来看,他们都支持一些消息和频道,都致力于高可用、高性能和高可扩展性。

      使用消息系统有很多优点:

        乘客向行程管理服务的 /trips 资源发送了 POST 请求,行程管理服务然后向乘客管理服务发送 GET 请求获取乘客信息,当乘客认证完成后,创建一个行程,并返回 201 响应。

        Leonard Richardson 为 REST 定义了一个成熟度模型,分为如下四个层次:

        • Level 0:web 服务使用 HTTP 作为传输方式,调用固定的 URL,每次请求指定方法和参数
        • Level 1:引入了资源的概念,要执行对资源的操作,请求通过 POST,指定要执行的操作和参数
        • Level 2:使用 HTTP 的语法来执行操作,例如:GET 表示获取,POST 表示创建,PUT 表示更新
        • Level 3:API 定义按照 HATEOAS(Hypertext As The Engine Of Application State)设计原则,基本思想 GET 请求返回资源的一些对资源允许操作的链接。例如:client 使用 GET 订单资源中包含的链接取消某一订单。HATEOAS 的一个优点就是无需在 client 代码中写入硬链接的 URL。此外,返回的资源信息中包含了对资源允许操作的链接,client 无需再猜测当前资源下所能做哪些操作了

        基于 HTTP 协议的优点:

        • 简单,为大家所熟悉
        • 可使用浏览器、postman,curl 之类的命令行测试 API
        • 支持 请求/响应 模式的通信
        • 不需要中间代理,减价系统架构

        HTTP 不足之处:

        • 只支持 请求/响应的交互
        • client 和 server 之间没有消息缓冲机制,要求交互时双方必须同时运行
        • client 需要知道每个 server实例 的url
        Thrift

        Apache Thrift 是 REST 的一个有趣的替代品,实现了跨语言的客户端和服务端RPC通信的框架,Thrift 提供了 C 语言风格的接口定义语言来定义 API,可以通过编译生成客户端Stub 和 服务端的骨架,可以生成多种语言的代码(包括 C++、Java、Python、PHP、Ruby、Erlang、Node.js)。

        Thrift 接口通常包含一个或多个服务,服务定义与 Java 接口类似,是一组强类型方法的集合。Thrift 能返回值,也可以定义为单向通信。如果需要返回值就需要实现 请求/响应风格的交互,客户端等待响应时可以抛出异常;单向通信就是通知模式,服务端不需要返回响应。

        Thrift 支持 JSON、二进制、压缩二进制等不同的消息格式。二进制解码比 JSON 更快,更为高效;压缩二进制比 JSON 空间利用率更高; JSON 则更易读。Thrift 也支持不同的通信协议:TCP 或 HTTP,TCP 比 HTTP 更加高效,而 HTTP 对防火墙、人及浏览器更加友好。

        消息格式

        选择一种支持多语言的消息格式非常重要,哪怕你只用一种语言实现微服务,谁又能保证以后不会使用新的语言呢?

        目前有文本和二进制两种格式。文本格式包括 JSON 和 XML。这种格式优点不仅可读,而且是自描述的。JSON中,对象的属性是键值对的集合;XML中,属性表示为命名的元素和值。消费者能选择感兴趣的值而忽略其他部分,对格式的修改也能容易的向后兼容。

        XML文档的结构是 XML Schema 定义的,随着时间的发展,开发者意识到 JSON 也需要一个类似的机制,方法一是使用 JSON Schema,要么独立使用,要么作为 Swagger 这类 IDL的一部分使用。

        文本格式的一大缺点是消息会变的冗长,尤其是 XML:因为消息是自描述的,每条消息除了值之外还包括属性的名称。另一大缺点是解析文本的开销略大,此时可以考虑二进制格式。

        二进制格式也很多,如果使用 Thrift,那么可以用二进制Thrift;如果使用其他消息格式,常用的还包括 Protocol Buffers 和 Apache Avro,两者都提供了 IDL 来定义消息结构。差异之处在于 Protocol Buffers 使用标记字段,而 Avro 消费者需要了解 Schema 来解析消息,使用 Protocol Buffers 时,API进化比 Avro 更容易。Martin Kleppmann 的  对Thrift、Protocol Buffers 和 Avor 进行了详细的比较。

        总结

        微服务需要使用进程间消息通信机制来交互,设计服务的通信模式时,需要考虑一下几个问题:服务如何交互、如何定义 API、如何升级 API,如何处理局部故障。微服务架构有两种 IPC 机制可用:异步消息机制和同步请求/响应机制。下篇文章中,我们会讨论微服务架构中的服务发现问题。

本类排行

今日推荐

热门手游