APP下载
报价宝  ›  科技  › 

微服务架构下的api闸道器服务

报价宝 来源:baojiabao.com 发布时间:2019-11-15 06:50:00 10月08日更新
报价宝综合消息微服务架构下的api闸道器服务

在决定以一组微服务来构建自己的应用时,你需要确定应用客户端如何与微服务互动。

在单体式程式中,通常只有一组冗余的或者负载均衡的服务提供点。在微服务架构中,每一个微服务暴露一组细粒度的服务提供点。在本篇文章中,我们来看它如何影响客户端到服务端通讯,并提出一种使用 API 闸道器的方法。简要概述

让我们想象一下,你要为一个购物应用程序开发一个原生移动客户端。你很可能需要实现一个产品详情页面,展示任何指定商品的资讯。

下图展示了 Amazon Android 应用在商品详情页显示的内容。

即使只是个智能手机应用,产品详情页面也显示了大量的资讯。该页面不仅包含基本的产品资讯(如名称、描述、价格),而且还显示了如下内容:

购物车中的商品数量历史订单客户评论低库存预警送货选项各种推荐,包括经常与该商品一起购买的其它商品、购买该商品的客户购买的其它商品、购买该商品的客户看过的其它商品其它的购物选择使用单体应用程序架构时,移动客户端通过向应用程序发起一次 REST 呼叫(GET api.company.com/productdetails/)来获取这些资料。负载均衡器将请求路由给 N 个相同的应用程序例项中的其中之一。然后,应用程序会查询各种数据库表,并将响应返回给客户端。

相反,若是采用微服务架构,显示在产品页上的资料会分布在不同的微服务上。下面列举了可能与产品详情页资料有关的一些微服务:

购物车服务——购物车中的件数订单服务——历史订单目录服务——商品基本资讯,如名称、图片和价格评论服务——客户的评论库存服务——低库存预警送货服务——送货选项、期限和费用,这些资讯单独从送货方 API 获取推荐服务——推荐商品

我们需要决定移动客户端如何访问这些服务。让我们看看有哪些方法。

1.客户端与微服务直接通讯

从理论上讲,客户端可以直接向每个微服务传送请求。每个微服务都有一个公开的端点(https ://.api.company.name)。该 URL 对映到微服务的负载均衡器,由后者负责在可用例项之间分发请求。为了获取产品详情,移动客户端将逐一向上文列出的 N 个服务传送请求。

遗憾的是,这种方法存在挑战和局限。问题之一是客户端需求和每个微服务暴露的细粒度 API 不匹配。在这个例子中,客户端需要传送 7 个独立请求。在更复杂的应用程序中,可能要传送更多的请求;按照 Amazon 的说法,他们在显示他们的产品页面时就呼叫了数百个服务。然而,客户端通过 LAN 传送许多请求,这在公网上可能会很低效,在移动网络上就根本不可行。这种方法还使得客户端程式码非常复杂。

客户端直接呼叫微服务的另一个问题是,部分服务使用的协议对 web 并不友好。一个服务可能使用 Thrift 二进位制 RPC,而另一个服务可能使用 AMQP 讯息传递协议。不管哪种协议对于浏览器或防火墙都不够友好,最好是内部使用。在防火墙之外,应用程序应该使用诸如 HTTP 和 WebSocket 之类的协议。

这种方法的另一个缺点是,它会使得微服务难以重构。随着时间推移,我们可能想要更改系统拆分成服务的方式。例如,我们可能合并两个服务,或者将一个服务拆分成两个或更多服务。然而,如果客户端与微服务直接通讯,那么执行这类重构就非常困难了。

由于上述三种问题的原因,客户端直接与服务器端通讯的方式很少在实际中使用。

2.使用 API 闸道器构建微服务

通常来说,使用 API 闸道器是更好的解决方式。API 闸道器是一个服务器,也可以说是进入系统的唯一节点。这与面向物件设计模式中的 Facade 模式很像。API 闸道器封装内部系统的架构,并且提供 API 给各个客户端。它还可能还具备授权、监控、负载均衡、快取、请求分片和管理、静态响应处理等功能。下图展示了一个适应当前架构的 API 闸道器。

API 闸道器负责服务请求路由、组合及协议转换。客户端的所有请求都首先经过 API 闸道器,然后由它将请求路由到合适的微服务。API 闸道器经常会通过呼叫多个微服务并合并结果来处理一个请求。它可以在 web 协议(如 HTTP 与 WebSocket)与内部使用的非 web 友好协议之间转换。

API 闸道器还能为每个客户端提供一个定制的 API。通常,它会向移动客户端暴露一个粗粒度的 API。以产品详情的场景为例,API 闸道器可以提供一个端点(/productdetails?productid=xxx),使移动客户端可以通过一个请求获取所有的产品详情。API 闸道器通过呼叫各个服务(产品资讯、推荐、评论等等)并合并结果来处理请求。

Netflix API 闸道器是一个很好的 API 闸道器例项。Netflix 流媒体服务提供给成百上千种类型的装置使用,包括电视、机顶盒、智能手机、游戏系统、平板电脑等等。

最初,Netflix 试图为他们的流媒体服务提供一个通用的 API。然而他们发现,由于各种各样的装置都有自己独特的需求,这种方式并不能很好地工作。如今,他们使用一个 API 闸道器,通过执行与针对特定装置的界面卡程式码,来为每种装置提供定制的 API。通常,一个界面卡通过呼叫平均 6 到 7 个后端服务来处理每个请求。Netflix API 闸道器每天处理数十亿请求。

API 闸道器的优点和缺点

如你所料,使用 API 闸道器有优点也有不足。使用 API 闸道器的最大优点是,它封装了应用程序的内部结构。客户端只需要同闸道器互动,而不必呼叫特定的服务。API 闸道器为每一类客户端提供了特定的 API,这减少了客户端与应用程序间的互动次数,还简化了客户端程式码。

API 闸道器也有一些不足。它增加了一个我们必须开发、部署和维护的高可用元件。还有一个风险是,API 闸道器变成了开发瓶颈。为了暴露每个微服务的端点,开发人员必须更新 API 闸道器。API闸道器的更新过程要尽可能地简单,这很重要;否则,为了更新闸道器,开发人员将不得不排队等待。不过,虽然有这些不足,但对于大多数现实世界的应用程序而言,使用 API 闸道器是合理的。

实现 API 闸道器

到目前为止,我们已经探讨了使用 API 闸道器的动力及其优缺点。下面让我们看一下需要考虑的各种设计问题。

效能和可扩充套件性

只有少数公司拥有 Netflix 这样的规模,需要每天处理每天需要处理数十亿请求。不管怎样,对于大多数应用程序而言,API 闸道器的效能和可扩充套件性都非常重要。因此,将 API 闸道器构建在一个支援异步、I/O 非阻塞的平台上是合理的。有多种不同的技术可以实现一个可扩充套件的 API 闸道器。在 JVM 上,可以使用一种基于 NIO 的框架,比如 Netty、Vertx、Spring Reactor 或 JBoss Undertow 中的一种。一个非常流行的非 JVM 选项是 Node.js,它是一个基于 Chrome JavaScript 引擎构建的平台。

另一个方法是使用 NGINX Plus。NGINX Plus 提供了一个成熟的、可扩充套件的、高效能 web 服务器和一个易于部署的、可配置可程式设计的反向代理。NGINX Plus 可以管理身份验证、访问控制、负载均衡请求、快取响应,并提供应用程序可感知的健康检查和监控。

使用响应式程式设计模型

API 闸道器通过简单地将请求路由给合适的后端服务来处理部分请求,而通过呼叫多个后端服务并合并结果来处理其它请求。对于部分请求,比如产品详情相关的多个请求,它们对后端服务的请求是独立于其它请求的。为了最小化响应时间,API 闸道器应该并发执行独立请求。

然而,有时候,请求之间存在依赖。在将请求路由到后端服务之前,API 闸道器可能首先需要呼叫身份验证服务验证请求的合法性。类似地,为了获取客户心愿单中的产品资讯,API 闸道器必须首先获取包含这些资讯的客户资料,然后再获取每个产品的资讯。关于 API 组合,另一个有趣的例子是 Netflix Video Grid。

使用传统的异步回拨方法编写 API 组合程式码会让你迅速坠入回拨地狱。程式码会变得混乱、难以理解且容易出错。一个更好的方法是使用响应式方法,以一种宣告式样式编写 API 闸道器程式码。响应式抽象概念的例子有 Scala 中的 Future、Java 8 中的 CompletableFuture 和 JavaScript 中的P romise,还有最初微软为 .NET 平台开发的 Reactive Extensions(RX)。Netflix 建立了 RxJava for JVM,专门用于他们的 API 闸道器。此外,还有 RxJS for JavaScript,它既可以在浏览器中执行,也可以在 Node.js 中执行。使用响应式方法能让你编写简单但高效的 API 闸道器程式码。

服务呼叫

基于微服务的应用程序是一个分散式系统,必须使用一种程序间通讯机制。有两种型别的程序间通讯机制可供选择。一种是使用异步的、基于讯息传递的机制。有些实现使用诸如 JMS 或 AMQP 那样的讯息代理,而其它的实现(如 Zeromq)则没有代理,服务间直接通讯。

另一种程序间通讯型别是诸如 HTTP 或 Thrift 那样的同步机制。通常,一个系统会同时使用异步和同步两种型别。它甚至还可能使用同一型别的多种实现。总之,API 闸道器需要支援多种通讯机制。

服务发现

API 闸道器需要知道它与之通讯的每个微服务的位置(IP 地址和埠)。在传统的应用程序中,或许可以硬连线这个位置,但在现代的、基于云的微服务应用程序中,这并不是一个容易解决的问题。基础设施服务(如讯息代理)通常会有一个静态位置,可以通过 OS 环境变数指定。但是,确定一个应用程序服务的位置没有这么简单。应用程序服务的位置是动态分配的,而且,单个服务的一组例项也会随着自动扩充套件或升级而动态变化。

总之,像系统中的其它服务客户端一样,API 闸道器需要使用系统的服务发现机制,可以是服务器端发现,也可以是客户端发现。下一篇文章将更详细地描述服务发现。现在,需要注意的是,如果系统使用客户端发现,那么 API 闸道器必须能够查询服务注册中心,这是一个包含所有微服务例项及其位置的数据库。

处理区域性失败

在实现 API 闸道器时,还需要处理区域性失败的问题。该问题出现在所有的分散式系统中。当一个服务呼叫另一个服务,而后者响应慢或不可用的时候,就会出现这个问题。API 闸道器不能因为无限期地等待下游服务而阻塞。不过,如何处理失败取决于特定的场景以及哪个服务失败。例如,在产品详情场景下,如果推荐服务无响应,那么 API 闸道器应该向客户端返回产品详情的其它内容,因为它们对使用者依然有用。推荐内容可以为空,也可以用一个固定的 TOP 10 列表取代。不过,如果产品资讯服务无响应,那么 API 闸道器应该向客户端返回一个错误资讯。

如果快取资料可用,那么 API 闸道器还可以返回快取资料。例如,鉴于产品价格不会频繁变动,如果价格服务不可用,API 闸道器可以返回快取的价格资料。资料可以由 API 闸道器自己快取,也可以储存在像 Redis 或 Memcached 之类的外部快取中。通过返回预设资料或者快取资料,API 闸道器可以确保系统故障不影响使用者体验。

在编写程式码呼叫远端服务方面,Netflix Hystrix 是一个格外有用的库。Hystrix 会暂停超出特定阈限的呼叫。它实现了一个“断路器(circuit breaker)”模式,可以防止客户端对无响应的服务进行不必要的等待。如果服务的错误率超出了设定的阈值,那么 Hystrix 会启动断路器,所有请求会立即失败并持续一定时间。Hystrix 允许使用者定义一个请求失败后的后援操作,比如从快取读取资料,或者返回一个预设值。如果你正在使用 JVM,那么你应该考虑使用 Hystrix;如果你正在使用一个非 JVM 环境,那么可以使用一个功能相同的库。

对于大多数基于微服务的应用程序而言,实现 API 闸道器,将其作为系统的唯一入口很有必要。API 闸道器负责服务请求路由、组合及协议转换。它为每个应用程序客户端提供一个定制的 API。API 闸道器还可以通过返回快取资料或预设资料遮蔽后端服务失败。接下来的章节,我们将探讨服务间通讯。

在单体应用中,各模组之间的呼叫是通过程式语言级别的方法或者函式来实现的。而基于微服务的分散式应用是执行在多台机器上的;一般来说,每个服务例项都是一个程序。

因此,如下图所示,服务之间的互动必须通过程序间通讯(IPC)来实现。

后面我们将会详细介绍 IPC 技术,现在我们先来看下设计相关的问题。

交付模式

当为某个服务选择 IPC 时,首先需要考虑服务之间的互动问题。客户端和服务器之间有很多的互动模式,我们可以从两个维度进行归类。第一个维度是一对一还是一对多:

• 一对一:每个客户端请求有一个服务例项来响应。

• 一对多:每个客户端请求有多个服务例项来响应。

第二个维度是这些互动式是同步还是异步:

• 同步模式:客户端请求需要服务端即时响应,甚至可能由于等待而阻塞。

• 异步模式:客户端请求不会阻塞程序,服务端的响应可以是非即时的。

下表显示了不同互动模式:

一对一的互动模式有以下几种方式:

1.请求/响应:一个客户端向服务器端发起请求,等待响应,客户端期望此响应即时到达。在一个基于执行绪的应用中,等待过程可能造成执行绪阻塞。

2.通知(也就是常说的单向请求):一个客户端请求传送到服务端,但是并不期望服务端响应。

3.请求/异步响应:客户端传送请求到服务端,服务端异步响应请求。客户端不会阻塞,而且被设计成预设响应不会立刻到达。

一对多的互动模式有以下几种方式:

释出/ 订阅模式:客户端释出通知讯息,被零个或者多个感兴趣的服务消费。释出/异步响应模式:客户端释出请求讯息,然后等待从感兴趣服务发回的响应。每个服务都是以上这些模式的组合。对某些服务,一个 IPC 机制就足够了;而对另外一些服务则需要多种 IPC 机制组合。下图展示了在使用者叫车时,打车应用内的服务是如何互动的。

上图中的服务通讯使用了通知、请求/响应、释出/订阅等方式。例如,乘客在移动端向“行程管理”服务传送通知,请求一次接送服务。“行程管理”服务通过使用请求/响应来唤醒“乘客服务”来验证乘客账号有效,继而建立此次行程,并利用释出/订阅来通知其它服务,其中包括定位可用司机的排程服务。

现在我们了解了互动模式,接下来我们一起来看看如何定义 API。定义 API

API 是服务端和客户端之间的契约。无论选择了何种 IPC 机制,重点是使用某种互动定义语言(IDL)来准确定义服务的 API。对于如何使用 API 优先的方式来定义服务,已经有了一些很好的讨论。你在开发服务之前,要定义服务界面并与客户端开发者共同讨论,后续只需要迭代 API 定义。这样的设计能够大幅提升服务的可用度。

在本文后半部分你将会看到,API 定义实质上依赖于选定的 IPC 机制。如果使用讯息机制,API 则由讯息频道(channel)和讯息型别构成;如果选择使用 HTTP 机制,API 则由 URL 和请求、响应格式构成。后面将会详细描述 IDL。

不断进化的 API

服务的 API 会随着时间而不断变化。在单体应用中,经常会直接修改 API 并更新所有的呼叫者。但是在基于微服务的应用中,即使所有的 API 的使用者都在同一应用中,这种做法也困难重重,通常不能强制让所有客户端都与服务保持同步更新。此外,你可能会增量部署服务的新版本,这时旧版本会与新版本同时执行。了解这些问题的处理策略至关重要。

对 API 变化的处理方式与变化的大小有关。有的变化很小,并且可以相容之前的版本;比如给请求或响应增加属性。在设计客户端和服务时,很有必要遵循健壮性原则。服务更新版本后,使用旧版 API 的客户端应该继续使用。服务为缺失的请求属性提供预设值,客户端则忽略任何额外的响应。使用 IPC 机制和讯息格式能够让你轻松改进 API。

然而有时候,API 需要进行大规模改动,并且不相容旧版本。鉴于不能强制让所有客户端立即升级,支援旧版 API 的服务还要再执行一段时间。如果你使用的是诸如 REST 这样的基于 HTTP 机制的 IPC,一种方法就是将版本号嵌入到 URL 中,每个服务例项可以同时处理多个版本。另一种方法是部署不同例项,每个例项处理一个版本的请求。

处理区域性失败

在上一篇关于 API 闸道器的文章中,我们了解到,分散式系统普遍存在区域性失败的问题。由于客户端和服务端是独立的程序,服务端可能无法及时响应客户端请求。服务端可能会因为故障或者维护而暂时不可用。服务端也可能会由于过载,导致对请求的响应极其缓慢。

以上篇文章中提及的产品页为例,假设推荐服务无法响应,客户端可能会由于无限期等待响应而阻塞。这不仅会导致很差的使用者体验,并且在很多应用中还会占用之前的资源,比如执行绪;最终,如下图所示,执行时耗尽执行绪资源,无法响应。

为了预防这种问题,设计服务时候必须要考虑部分失败的问题。

Netfilix 提供了一个比较好的解决方案,具体的应对措施包括:

网络超时:在等待响应时,不设定无限期阻塞,而是采用超时策略。使用超时策略可以确保资源不被无限期占用。限制请求的次数:可以为客户端对某特定服务的请求设定一个访问上限。如果请求已达上限,就要立刻终止请求服务。断路器模式(Circuit Breaker Pattern):记录成功和失败请求的数量。如果失效率超过一个阈值,触发断路器使得后续的请求立刻失败。如果大量的请求失败,就可能是这个服务不可用,再发请求也无意义。在一个失效期后,客户端可以再试,如果成功,关闭此断路器。提供回滚:当一个请求失败后可以进行回滚逻辑。例如,返回快取资料或者一个系统预设值。Netflix Hystrix 是一个实现相关模式的开源库。如果使用 JVM,推荐使用Hystrix。而如果使用非 JVM 环境,你可以使用类似功能的库。IPC 技术

现在有很多不同的 IPC 技术。服务间通讯可以使用同步的请求/响应模式,比如基于 HTTP 的 REST 或者 Thrift。另外,也可以选择异步的、基于讯息的通讯模式,比如 AMQP 或者 STOMP。此外,还可以选择 JSON 或者 XML 这种可读的、基于文字的讯息格式。当然,也还有效率更高的二进位制格式,比如 Avro 和 Protocol Buffer。在讨论同步的 IPC 机制之前,我们先了解异步的 IPC 机制。

基于讯息的异步通讯

使用讯息模式的时候,程序之间通过异步交换讯息讯息的方式通讯。客户端通过向服务端传送讯息提交请求,如果服务端需要回复,则会发送另一条独立的讯息给客户端。由于异步通讯,客户端不会因为等待而阻塞,相反会认为响应不会被立即收到。

讯息由资料头(例如传送方这样的元资料)和讯息正文构成。讯息通过渠道传送,任何数量的生产者都可以传送讯息到渠道,同样,任何数量的消费者都可以从渠道中接受资料。频道有两类,包括点对点渠道和释出/订阅渠道。点对点渠道会把讯息准确的传送到从渠道读取讯息的使用者,服务端使用点对点来实现之前提到的一对一互动模式;而释出/订阅则把讯息投送到所有从渠道读取资料的使用者,服务端使用释出/订阅渠道来实现上面提到的一对多互动模式。

下图展示了打车软件如何使用释出/订阅:

通过向释出/订阅渠道写入一条建立行程的讯息,行程管理服务会通知排程服务有新的行程请求。排程服务发现可用的司机后会向释出/订阅渠道写入一条推荐司机的讯息,并通知其它服务。

有多种讯息系统可供选择,最好选择支援多程式语言的。有的讯息系统支援 AMQP 和 STOMP 这样的标准协议,有的则支援专利协议。也有大量的开源讯息系统可用,譬如 RabbitMQ、Apache Kafka、Apache ActiveMQ 和 NSQ。宏观上,它们都支援一些讯息和渠道格式,并且努力提升可靠性、高效能和可扩充套件性。然而,细节上,它们的讯息模型却大相径庭。

使用讯息机制有很多优点:

解耦客户端和服务端:客户端只需要将讯息传送到正确的渠道。客户端完全不需要了解具体的服务例项,更不需要一个发现机制来确定服务例项的位置。讯息缓冲:在 HTTP 这样的同步请求/响应协议中,所有的客户端和服务端必须在互动期间保持可用。而在讯息模式中,讯息中间人将所有写入渠道的讯息按照伫列方式管理,直到被消费者处理。也就是说,线上商店可以接受客户订单,即使下单系统很慢或者不可用,只要保持下单讯息进入伫列就好了。客户端-服务端的灵活互动:讯息机制支援以上说的所有互动模式。清晰的程序间通讯:基于 RPC 的通讯机制试图让唤醒远端服务端像呼叫本地服务一样,然而,囿于物理定律和可能的区域性失败,这二者大不相同。讯息机制能让这些差异直观明确,开发者不会产生安全错觉。然而,讯息机制也有自己的缺点:

额外的操作复杂性:讯息系统需要单独安装、配置和部署。讯息broker(代理)必须高可用,否则系统可靠性将会受到影响。实现基于请求/响应互动模式的复杂性:请求/响应互动模式需要完成额外的工作。每个请求讯息必须包含一个回复渠道 ID 和相关 ID。服务端传送一个包含相关 ID 的响应讯息到渠道中,使用相关 ID 来将响应对应到发出请求的客户端。这种情况下,使用一个直接支援请求/响应的 IPC 机制会更容易些。现在我们已经了解了基于讯息的 IPC,接下来我们来看看基于请求/响应模式的 IPC。

基于请求/响应的同步 IPC

使用同步的、基于请求/响应的 IPC 机制的时候,客户端向服务端传送请求,服务端处理请求并返回响应。一些客户端会由于等待服务端响应而被阻塞,而另外一些客户端可能使用异步的、基于事件驱动的客户端程式码,这些程式码可能通过 Future 或者 Rx Observable 封装。然而,与使用讯息机制不同,客户端需要响应及时返回。这个模式中有很多可选的协议,但最常见的两个协议是 REST 和 Thrift。首先我们来了解 REST。

REST

当前很流行开发 RESTful 风格的 API。REST 基于 HTTP 协议,其核心概念是资源典型地代表单一业务物件或者一组业务物件,业务物件包括“消费者”或“产品”。REST 使用 HTTP 协议来控制资源,通过 URL 实现。譬如,GET 请求会返回一个资源的包含资讯,可能是 XML 文件或 JSON 物件格式。POST 请求会建立新资源,而 PUT 请求则会更新资源。REST 之父 Roy Fielding 曾经说过:

REST 提供了一系列架构系统引数,作为整体使用,强调元件互动的扩充套件性、界面的通用性、元件的独立部署、以及减少互动延迟的中介软件,它强化安全,也能封装遗留系统。

下图展示了打车软件如何使用 REST。

乘客通过移动端向行程管理服务的 /trips 资源提交了一个 POST请求。行程管理服务收到请求之后,会发送一个 GET 请求到乘客管理服务以获取乘客资讯。当确认乘客资讯之后,随即建立一个行程,并向移动端返回 201 响应。

很多开发者都表示他们基于 HTTP 的 API 是 RESTful 风格。但是,如同 Fielding 在他的部落格中所说,并非所有这些 API 都是 RESTful。Leonard Richardson(注:与本文作者 Chris 无任何关系)为 REST 定义了一个成熟度模型,具体包含以下四个层次:

Level 0:本层级的 Web 服务只是使用 HTTP 作为传输方式,实际上只是远端方法呼叫(RPC)的一种具体形式。SOAP 和 XML-RPC 都属于此类。Level 1:Level 1 层级的 API 引入了资源的概念。要执行对资源的操作,客户端发出指定要执行的操作和任何引数的 POST 请求。Level 2:Level 2 层级的 API 使用 HTTP 语法来执行操作,譬如 GET 表示获取、POST 表示建立、PUT 表示更新。如有必要,请求引数和主体指定操作的引数。这能够让服务影响 web 基础设施服务,如快取 GET 请求。Level 3:Level 3 层级的 API 基于 HATEOAS(Hypertext As The Engine Of Application State)原则设计,基本思想是在由 GET请求返回的资源资讯中包含连结,这些连结能够执行该资源允许的操作。例如,客户端通过订单资源中包含的连结取消某一订单,GET 请求被发送去获取该订单。HATEOAS 的优点包括无需在客户端程式码中写入硬连结的 URL。此外,由于资源资讯中包含可允许操作的连结,客户端无需猜测在资源的当前状态下执行何种操作。使用基于 HTTP 的协议有如下好处:

HTTP 非常简单并且大家都很熟悉。可以使用浏览器扩充套件(比如 Postman)或者 curl 之类的命令列来测试 API。内建支援请求/响应模式的通讯。HTTP 对防火墙友好。不需要中间代理,简化了系统架构。不足之处包括:

只支援请求/响应模式互动。尽管可以使用 HTTP 通知,但是服务端必须一直发送 HTTP 响应。由于客户端和服务端直接通讯(没有代理或者缓冲机制),在互动期间必须都保持线上。客户端必须知道每个服务例项的 URL。如前篇文章“API 闸道器”所述,这也是个烦人的问题。客户端必须使用服务例项发现机制。开发者社群最近重新认识到了 RESTful API 界面定义语言的价值,于是诞生了包括 RAML 和 Swagger 在内的服务框架。Swagger 这样的 IDL 允许定义请求和响应讯息的格式,而 RAML 允许使用 JSON Schema 这种独立的规范。对于描述 API,IDL 通常都有工具从界面定义中生成客户端存根和服务端框架。

Thrift

Apache Thrift 是一个很有趣的 REST 的替代品,实现了多语言 RPC 客户端和服务端呼叫。Thrift 提供了一个 C 风格的 IDL 定义 API。通过 Thrift 编译器能够生成客户端存根和服务端框架。编译器可以生成多种语言的程式码,包括 C++、Java、Python、PHP、Ruby, Erlang 和 Node.js。

Thrift 界面由一个或多个服务组成,服务定义与 Java 界面类似,是一组强型别方法的集合。Thrift 能够返回(可能无效)值,也可以被定义为单向。返回值的方法能够实现互动的请求/响应模式。客户端等待响应,可能会丢掷异常。单向方法与互动的通知模式相对应。服务端不会发送响应。

Thrift 支援 JSON、二进位制和压缩二进位制等多种讯息格式。由于解码更快,二进位制比 JSON 更高效;如名称所称,压缩二进位制格式可以提供更高级别的压缩效率;同时 JSON 则易读。Thrift 也能够让你选择传输协议,包括原始 TCP 和 HTTP。原始 TCP 比 HTTP 更高效,然而 HTTP 对于防火墙、浏览器和使用者来说更友好。

讯息格式

了解 HTTP 和 Thrift 后,我们要考虑讯息格式的问题。如果使用讯息系统或者 REST,就需要选择讯息格式。像 Thrift 这样的 IPC 机制可能只支援少量讯息格式,或许只支援一种格式。无论哪种情况,使用跨语言的讯息格式非常重要。即便你现在使用单一语言实现微服务,但很有可能未来需要用到其它语言。

目前有文字和二进位制这两种主要的讯息格式。文字格式包括 JSON 和 XML。这种格式的优点在于不仅可读,而且是自描述的。在 JSON 中,物件的属性是名称-值对的集合。与此类似,在 XML 中,属性则表示为命名的元素和值。消费者能够从中选择感兴趣的值同时忽略其它部分。相应地,对讯息格式的小幅度修改也能容易地向后相容。

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

文字讯息格式的一大缺点是讯息会变得冗长,特别是 XML。由于讯息是自描述的,所以每个讯息都包含属性和值。另外一个缺点是解析文字的负担过大。所以,你可能需要考虑使用二进位制格式。

二进位制的格式也有很多。如果使用的是 Thrift RPC,那可以使用二进位制 Thrift。如果选择讯息格式,常用的还包括 Protocol Buffers 和 Apache Avro,二者都提供型别 IDL 来定义讯息结构。差异之处在于 Protocol Buffers 使用新增标记的字段(tagged fields),而 Avro 消费者需要了解模式来解析讯息。

总结

微服务必须使用程序间通讯机制来互动。在设计服务的通讯模式时,你需要考虑几个问题:服务如何互动,每个服务如何标识 API,如何升级 API,以及如何处理区域性失败。微服务架构异步讯息机制和同步请求/响应机制这两类 IPC 机制可用。在下一篇文章中,我们将会讨论微服务架构中的服务发现问题。

文章标签: 报价宝 降噪耳机价格 耳机价格 红米手机价格 华为手机价格 小米手机价格 电视机价格 笔记本电脑价格 笔记本价格 汽车价格 报价宝 笔记本价格 笔记本电脑价格 电视机价格 红米手机价格