微服务从设计到部署(二)使用 API 网关

连接https://github.com/oopsguy/microservices-from-design-to-deployment-chinese
译者Oopsguyhtml

本书的七个章节是关于设计、构建和部署微服务。第一章介绍了微服务架构模式。它阐述使用微服务的优势与缺点,以及尽管如此,微服务一般是复杂应用的理想选择。该系列的第二篇文章将探讨使用 API 网关构建微服务。java

当您选择将应用程序构建成为一组微服务时,您须要决定应用程序客户端将如何与微服务进行交互。单体应用程序只有一组端点(endpoint),一般使用复制(replicated)结合负载均衡来分配流量。react

然而,在微服务架构中,每一个微服务都暴露一组一般比较细颗粒的端点。在本文中,咱们将研究如何改进客户端通讯,并提出一个使用 API 网关的方案。nginx

2.一、简介

咱们假设您正在为一个购物应用开发一个原生移动客户端。您可能须要实现一个产品详细信息页面,用于展现给定商品的信息。git

例如,图 2-1 展现了在 Amazon 的 Android 移动应用中的滚动产品信息时所看的内容。github

图 2-一、一个简单的购物应用

即便这是一个智能手机应用,产品详细信息页面展现了不少信息。例如,不只有基本的产品信息,如名称、描述和价格,页面还展现了:web

  1. 购物车中的物品数量
  2. 订单历史
  3. 客户评论
  4. 低库存警告
  5. 配送选项
  6. 各类推荐,包括了买了此产品的客户常常买的其余产品
  7. 选择性购买选项

在使用单体应用架构的状况下,移动客户端经过对应用程序进行单个 REST 调用来检索此数据,例如:数据库

GET api.company.com/productdetails/productId

负载均衡器将请求路由到几个相同应用程序实例中的其中一个。以后,应用程序查询各个数据库表并返回响应给客户端。相比之下,当使用微服务架构时,产品详细页面上展现的数据来自多个微服务。如下是一些可能拥有特定商品页面展现的数据的微服务:编程

  • 订单服务 - 订单历史
  • 目录(catalog)服务 - 基本的产品信息,如产品名称、图片和价格
  • 评价服务 - 客户评价
  • 库存服务 - 低库存警告
  • 配送服务 - 配送选项、期限和费用,由配送方的 API 单独提供
  • 推荐服务 - 推荐类目

图 2-二、将移动客户端的需求映射到相关的微服务

咱们须要决定移动客户端如何访问这些服务。让咱们来看看有哪些方式。后端

2.二、客户端与微服务直接通讯

理论上,客户端能够直接向每一个微服务发送请求。每一个微服务都有一个公开的端点:

https://serviceName.api.company.name

该 URL 将映射到用于跨可用实例分发请求的微服务负载均衡器,要检索特定的产品页面信息,移动客户端将向上述的每一个微服务发送请求。

不幸的是,这种方式存在着挑战与限制。第一个问题是客户端的需求与每一个微服务暴露的细粒度的 API 不匹配。此示例中,客户端须要进行七次单独请求。若是在更加复杂的应用中,它可能须要作更多的工做。例如,Amazon 展现了在产品页面渲染中如何牵涉到数百个微服务。虽然客户端能够经过 LAN 发送许多请求,但在公共互联网下效率低下,在移动网络必然是不切实际。

客户端直接调用微服务的另外一个问题是有些可能使用了不是 web 友好的协议。一个服务可能使用 Thrift 二进制 RPC,而另外一个则可能使用 AMQP 消息协议。这两个协议不管是对于浏览器仍是防火墙都是不友好的,最好是在内部使用。应用程序应该在防火墙以外使用 HTTP 或者 WebSocket 之类的协议。

这种方法的另外一个缺点是它难以重构微服务。随着时间推移,咱们可能会想改变系统划分服务。例如,咱们可能会合并两个服务或者将服务拆分为两个或者多个。然而,若是客户端直接与服务进行通讯,实施这类的重构将变得很是困难。

因为存在这些问题,不多有客户端直接与微服务进行通讯。

2.三、使用 API 网关

一般更好的方法是使用 API 网关。一个 API 网关是一个服务器,是系统的单入口点。它相似于面向对象设计模式中的门面(Facade)模式。API 网关封装了内部系统架构,并针对每一个客户端提供一个定制的 API。它还可用于认证、监控、负载均衡、缓存和静态响应处理。

图 2-3 展现了 API 一般如何整合架构

使用 API 网关的微服务

API 网关负责请求路由、组合和协议转换。全部的客户端请求首先经过 API 网关,以后请求被路由到适当的服务。API 网关一般会经过调用多个微服务和聚合结果来处理一个请求。它能够在 Web 协议(如 HTTP 和 WebSocket)和用于内部的非 Web 友好协议之间进行转换。

API 还能够为每一个客户端提供一个定制的 API。它一般会为移动客户端暴露一个粗粒度的 API。例如,考虑一下产品详细信息场景。API 网关能够提供一个端点 /productdetails?productid=xxx,如图 2-3 所示,一个使用了 API 网关的微服务。容许移动客户端经过一个单独的请求来检索全部产品详细信息。API 网关经过调用各类服务(产品信息、推荐、评价等)并组合结果。

API 网关的一个很好的案例是 Netflix API 网关。Netflix 流媒体服务可用于数百种不一样类型的设备,包括电视机、机顶盒、智能手机、游戏机和平板电脑等。起初,Netflix 尝试为他们的流媒体服务提供一个通用的 API。可是,他们发现因为设备种类繁多,而且他们各自有着不一样需求,因此并非能很好地运做。现在,他们使用了 API 网关,经过运行特定设备适配代码来为每一个设备提供一个定制 API。

2.四、API 网关的优势和缺点

正如您所料,使用 API 网关一样存在好处与坏处。使用 API 网关的主要好处是它封装了应用程序的内部结构。客户端只须要与网关通讯,而没必要调用特定的服务。API 网关为每种类型的客户端提供了特定的 API,减小了客户端与应用程序之间的往返次数。它还简化了客户端代码。

API 网关也存在一些缺点,它是另外一个高度可用的组件,须要开发、部署和管理。还有另外一个风险是 API 网关可能会成为开发瓶颈。开发人员必须更新 API 网关以暴露每一个微服务的端点。

重要的是更新 API 网关的过程应尽量地轻一些。不然,开发人员将被迫排队等待网关更新。尽管 API 网关存在这些缺点,但对于大多数的真实应用来讲,使用 API 是合理的。

2.五、实施 API 网关

咱们已经了解了使用 API 网关的动机与权衡。接下来让咱们看看您须要考虑的各类设计问题。

2.5.一、性能与可扩展性

只有少数公司能达到 Netflix 的运营规模,天天须要处理数十亿的请求。然而,对于大多数应用来讲,API 网关的性能和可扩展性是至关重要的。所以,在一个支持异步、非阻塞 I/O 平台上构建 API 网关是有必要的。可使用不一样的技术来实现一个可扩展的 API 网关。在 JVM 上,您可使用基于 NIO 的框架,如Netty、Vertx、Spring Reactor 或者 JBoss Undertow。一个流行的非 JVM 选择是使用 Node.js,它是一个创建在 Chrome 的 JavaScript 引擎的平台。另外一个选择是使用 NGINX Plus。

NGINX Plus 提供了一个成熟、可扩展和高性能的 Web 服务器和反向代理,它易于部署、配置和编程。NGINX Plus 能够管理身份验证、访问控制、负载均衡请求、缓存响应,而且提供了应用程序健康检查和监控功能。

2.5.二、使用响应式编程模型

API 网关经过简单地把他们(请求)路由到适当的后端服务来处理一些请求。它经过调用多个后端服务并聚合结果来处理其余请求。对于某些请求,如产品详细信息请求,对后端服务请求而言是彼此独立的。为了缩短响应时间到最小,API 网关应该并发执行独立请求。

然而,有时候,请求是相互依赖的。首先,API 网关可能须要在将请求路由到后端服务以前,经过调用验证服务来验证请求。一样,为了从客户的愿望清单中获取关于产品的信息,API 网关首先必须检索包含该信息的客户资料,而后检索每一个产品的信息。API 组合的另外一个有趣的案例是 Netflix 视频网格

使用传统的异步回调方式来编写 API 组合代码会很快使你陷入回调地狱。代码将会变得杂乱,难以理解,而且容易出错。一个更好的方式是使用响应式方法以声明式编写 API 网关代码。响应式抽象的例子包括 Scala 的 Future、Java 8 中的 CompletableFuture 和 JavaScript 中的 Promise。还有 Reactive Extensions(也称为 Rx 或 ReactiveX),最初由 Microsoft 为 .NET 平台开发。Netflix 为 JVM 建立了 RxJava,专门应用于其 API 网关。还有用于 JavaScript 的 RxJS,它能够在浏览器和 Node.js 中运行。使用响应式方式可以让您可以编写出简单而高效的 API 网关代码。

2.5.三、服务调用

一个基于微服务的应用程序是一个分布式系统,必须使用一个进程间(inter-process)通讯机制。有两种进程间通讯方案。一是使用基于消息的异步机制。某些实现采用了消息代理,如 JMS 和 AMQP。其余采用无代理的方式直接与服务通讯,如 Zeromq。

另外一种类型的进程间通讯采用了同步机制,如 HTTP 和 Thrift。系统一般会同时使用异步和同步方式。甚至能够为每种方式应用多个实现。所以,API 网关须要支持各类通讯机制。

2.5.四、服务发现

API 网关须要知道与其通讯的每一个微服务的位置(IP 地址和端口)。传统应用程序中,您能够将这些位置硬编码,但在现代基于云的微服务应用程序中,找到所需的位置不是一个简单的问题。

基础设施服务(好比消息代理)一般都有一个能够经过系统环境变量来指定的静态位置。可是,要肯定应用程序服务的位置并非那么容易。

应用服务能够动态分配位置。此外,因为自动扩展与升级,一个服务的整组实例能够动态变动。所以,API 网关与系统中的任何其余服务客户端同样,须要使用系统的服务发现机制:服务端发现客户端发现。 第4章中更详细地描述了服务发现。如今须要注意的是,若是系统使用客户端发现,API 网关必须可以查询服务注册表,该注册表是全部微服务实例及其位置的数据库。

2.5.五、处理局部故障

实施 API 网关时必须解决的另外一个问题是局部故障问题。当一个服务调用另外一个响应缓慢或者不可用的服务时,全部分布式系统都会出现此问题。API 网关不该该无限期地等待下游服务。可是,如何处理故障问题取决于特定的方案和哪些服务发生故障。例如,若是推荐服务在获取产品详细信息时没有响应,API 网关应将其他的产品详细信息返回给客户端,由于它们对用户仍然有用。建议能够是空的,也能够用其余代替,例如硬编码的十强名单。然而,若是产品信息服务没有响应,那么 API 网关应该向客户端返回错误。

若是能够,API 网关还能够返回缓存数据。例如,因为产品价格变化不大,若是价格服务不可用,API 网关能够返回被缓存的价格数据。数据能够由 API 网关缓存或存储在外部缓存中,如 Redis 或者 Memcached。API 网关经过返回默认数据或缓存数据,确保了系统发生故障时最小程度上影响到用户体验。

Netflix Hystrix 是用于编写调用远程服务代码的一个很是有用的库。Hystrix 可使超出指定阈值的调用超时。它实现了断路器模式,防止客户端没必要要地等待无响应的服务。若是服务的错误率超过指定阈值,Hystrix 将会跳闸,全部请求将在指定的时间内当即失败。Hystrix 容许您在请求失败时定义回退操做,例如从缓存读取或返回默认值。若是您正在使用 JVM,那么您必定要考虑使用 Hystrix。若是您是在非 JVM 环境中运行,则应使用同等做用的库。

2.六、总结

对于大多数基于微服务的应用程序来讲,实现一个 API 网关是颇有意义的,API 网关充当着系统的单入口点,而且负责请求路由,组合和协议转换。它为每一个应用程序客户端提供了一个自定义 API。API 网关还能够经过返回缓存或默认数据来掩盖后端服务故障。在下一章中,咱们将介绍服务间的通讯。

微服务实战:NGINX Plus 做为 API 网关

by Floyd Smith

本章讨论了 API 网关如何做为系统的单入口点。它能够处理诸如负载均衡、缓存、监控和协议转换等其余功能 —— 当 NGINX 充当一个反向代理服务器时,能够做为系统的单入口点,而且支持全部提到的一个 API 网关具备的附加功能。所以使用 NGINX 做为 API 网关的主机能够很好地工做。

将 NGINX 做为 API 网关并非本书最开始的想法。NGINX Plus 是用于管理和保护基于 HTTP 的 API 流量的领先平台。您能够实现本身的 API 网关或使用现有的 API 管理平台,其中许多使用了 NGINX。

使用 NGINX Plus 做为 API 网关的理由包括:

  • 访问管理 - 上至典型的 Web 应用级别,下至每一个个体微服务级别,您均可以使用各类访问控制列表(ACL)方法,而且能够轻松实现 SSL/TLS。
  • 可管理性与弹性 - 您可使用 NGINX 的动态从新配置 API、Lua 模块、Perl 来更新基于 NGINX Plus 的 API 服务器,也能够经过 Chef、Puppet、ZooKeeper 或 DNS 来改变。
  • 与第三方工具集成 - NGINX Plus 已经能够与某些先进的工具集成在一块儿,如 3scaleKongMuleSoft 集成平台(仅列举在 NGINX 网站上说起的工具)。

NGINX Plus 被普遍用做 NGINX 微服务参考架构中的 API 网关。利用在这里收集的文章以及 MRA (微服务参考架构)来了解如何在您本身的应用程序中实现这一点。

本系列所有译文

相关连接

相关文章
相关标签/搜索