所有文章 > API开发 > 构建微服务架构:实现 API 网关的最佳实践
构建微服务架构:实现 API 网关的最佳实践

构建微服务架构:实现 API 网关的最佳实践

当应用程序构建为一组微服务时,需要决定客户端与微服务之间的交互方式。整体应用程序通常只有一组端点(一般是复制和负载均衡的),而在微服务架构中,每个微服务则会公开一组细粒度的端点。本文探讨了这一点对客户端与应用程序通信的影响,并提出了一种使用 API 网关的方法。

介绍

在为购物应用程序开发本机移动客户端时,可能需要实现一个产品详细信息页面,以显示有关特定产品的信息。

例如,在亚马逊 Android 移动应用程序中,产品详细信息页面展示了丰富的信息。该页面不仅包括基本的产品信息(如名称、描述和价格),还显示:

  • 购物车中的商品数量
  • 订单历史
  • 客户评价
  • 库存低警告
  • 运输选项
  • 各种推荐,包括与该产品经常一起购买的其他产品、购买该产品的顾客购买过的其他产品,以及查看该产品的客户查看的其他产品
  • 其他购买选择

在使用整体应用程序架构时,移动客户端通过单个 REST 调用(GET api.company.com/productdetails/)来检索数据。负载均衡器会将请求路由到 N 个相同的应用程序实例之一,应用程序随后查询各种数据库表并将响应返回给客户端。

而在微服务架构中,产品详细信息页面上显示的数据由多个微服务管理。以下是一些可能负责示例产品详细信息页面上数据的微服务:

  • 购物车服务 – 购物车中的商品数量
  • 订单服务 – 订单历史
  • 目录服务 – 基本产品信息,例如名称、图像和价格
  • 评论服务 – 客户评论
  • 库存服务 – 低库存警告
  • 运输服务 – 运输选项、截止日期和费用,分别从运输提供商的 API 中获取
  • 推荐服务 – 建议的商品

接下来需要决定移动客户端如何访问这些服务。让我们看看可选方案。

客户端到微服务的直接通信

理论上,客户端可以直接向每个微服务发出请求。每个微服务都有一个公共端点 (https://.api.company.name),该 URL 会映射到微服务的负载均衡器,从而在可用实例之间分发请求。为了检索产品详细信息,移动客户端将向列出的多个服务发出请求。

然而,这种方法存在挑战和限制。首先,客户端需求与每个微服务公开的细粒度 API 之间可能不匹配。客户端必须发出多个单独请求,复杂应用程序中请求数量可能更多。例如,亚马逊描述了数百种服务参与其产品页面的呈现。虽然在局域网内可以发出如此多的请求,但在公共互联网上可能效率低下,移动网络上则更为不切实际。此外,这种方法使客户端代码变得复杂。

另一个问题是某些微服务可能使用不适合 Web 的协议。例如,一项服务可能使用 Thrift 二进制 RPC,而另一项服务可能使用 AMQP 消息传递协议,这些协议在浏览器或防火墙面前并不友好,适合内部使用。因此,应用程序应在防火墙外部使用 HTTP 和 WebSocket 等协议。

此外,这种方法还会使微服务的重构变得困难。随着时间的推移,可能需要调整服务的划分,例如合并或拆分服务。如果客户端直接与服务通信,执行这种重构将非常复杂。

基于以上问题,客户端直接与微服务通信的方案几乎没有意义。

使用 API 网关

一种更有效的方式是采用 API 网关。API 网关是一个服务器,充当系统的单一入口点,类似于面向对象设计中的外观模式。它封装了内部系统架构,并为每个客户端提供量身定制的 API。此外,API 网关还可能承担其他职责,如身份验证、监控、负载均衡、缓存、请求整形和静态响应处理。

API 网关负责请求的路由、组合和协议转换。所有来自客户端的请求首先经过 API 网关,然后路由到适当的微服务。API 网关通常通过调用多个微服务并聚合结果来处理请求,能够在 HTTP 和 WebSocket 等 Web 协议与不友好的内部协议之间进行转换。

API 网关还可以为每个客户端提供自定义 API,通常为移动客户端公开粗粒度的 API。例如,在产品详细信息场景中,API 网关可以提供端点 (/productdetails?productid=xxx),使移动客户端能够通过单个请求检索所有产品详细信息。API 网关会通过调用各种服务(如产品信息、推荐和评论等)并组合结果来处理请求。

一个很好的例子是 Netflix 的 API 网关。Netflix 流媒体服务可在数百种不同类型的设备上使用,包括电视、机顶盒、智能手机、游戏系统和平板电脑。最初,Netflix 尝试为流媒体服务提供一种通用的 API,但由于设备种类繁多且需求各异,效果不佳。如今,他们使用 API 网关,通过运行特定于设备的适配器代码来提供量身定制的 API。适配器通常通过调用 6-7 个后端服务来处理每个请求,Netflix 的 API 网关每天处理数十亿次请求。

API 网关的优点和缺点

使用 API 网关既有优点也有缺点。一个主要好处是它封装了应用程序的内部结构,客户端无需调用特定服务,只需与网关交互即可。API 网关为每种客户端提供特定的 API,从而减少了客户端和应用程序之间的往返次数,简化了客户端代码。

然而,API 网关也有一些缺点。它是一个必须开发、部署和管理的高可用性组件,并且可能成为开发的瓶颈。开发人员需要更新 API 网关以公开每个微服务的端点,因此确保更新过程尽可能轻量级至关重要。否则,开发人员将面临等待更新网关的困境。

尽管存在这些缺点,对于大多数现实世界的应用程序来说,使用 API 网关仍然是有意义的。

实施 API 网关

在了解了使用 API 网关的动机和权衡后,接下来需要考虑的设计问题包括:

性能和可扩展性

虽然只有少数公司能达到 Netflix 的规模,每天处理数十亿个请求,但对于大多数应用程序而言,API 网关的性能和可扩展性同样重要。因此,建议在支持异步、非阻塞 I/O 的平台上构建 API 网关。可以使用多种技术来实现可扩展的 API 网关,如基于 NIO 的框架(如 Netty、Vertx、Spring Reactor 或 JBoss Undertow),或使用流行的非 JVM 选项 Node.js。另一个选择是 NGINX Plus,提供成熟、高性能的服务器和反向代理,易于部署和配置。

使用反应式编程模型

API 网关通过将请求路由到适当的后端服务来处理请求,对于某些请求,尤其是独立的请求,API 网关应该并发执行以最小化响应时间。然而,有时请求之间存在依赖性,例如在调用身份验证服务后再路由到后端服务。传统的异步回调方法可能导致代码混乱,难以维护,因此采用响应式编程的方法更为高效。使用 Scala Futures、Java 8 CompletableFutures 或 JavaScript Promise 等响应式抽象,可以让 API 网关代码更加简单明了。

服务调用

基于微服务的应用程序作为分布式系统,需使用进程间通信机制。进程间通信可以是异步的、基于消息的机制(如 JMS 或 AMQP)或同步的机制(如 HTTP 或 Thrift)。API 网关需要支持多种通信机制,以应对不同的实现需求。

服务发现

API 网关需要知道与之通信的每个微服务的位置。在传统应用程序中,可以硬连线位置,但在现代基于云的微服务应用中,服务位置是动态分配的。API 网关需要使用服务发现机制(如服务器端发现或客户端发现),并能够查询服务注册表以获取所有微服务实例及其位置。

处理部分故障

部分故障是分布式系统中的常见问题。API 网关不应无限期阻塞以等待下游服务,处理方式应根据具体情况而定。例如,如果推荐服务无响应,API 网关应返回其余有效的产品详细信息,可能将推荐列表替换为预设的热门列表。而如果产品信息服务无响应,则应向客户端返回错误。

此外,API 网关可以返回缓存数据(如定价信息),确保在服务不可用时不影响用户体验。Netflix 的 Hystrix 库是处理远程服务调用的有用工具,能够超时调用并实现断路器模式,避免不必要的等待。对于使用 JVM 的应用,Hystrix 是一个值得考虑的选项,而在非 JVM 环境中则应使用等效的库。

概括

对于大多数基于微服务的应用程序,实现 API 网关是有意义的,因为它充当系统的单一入口点。API 网关负责请求的路由、组合和协议转换,并为每个客户端提供定制的 API。此外,它还可以通过返回缓存或默认数据来掩盖后端服务中的故障。在本系列的下一篇文章中,将探讨服务之间的通信。

原文链接:Building Microservices: Using an API Gateway

#你可能也喜欢这些API文章!