文章
作者:Phil Wilkins
2017 年 6 月
微服务和新的第三代 API 管理功能是天然的技术合作伙伴。(微)服务为单一功能提供执行逻辑,第三代 API 管理可用于控制每个服务与外部环境之间的接口以及各个(微)服务之间的接口。Luis Weir 在“第三代 API 管理”一文中介绍了 API 管理功能的发展历程,以及第三代的 API 管理的哪些功能可让 API 管理与(微)服务良好地融合。在本文中,我们将探讨注册表在(微)服务环境中的作用以及它与 API 管理的关系。我们并不会深入探讨任何具体的解决方案,但我们会提及一些较为知名的方案,并提供相应的链接,以便您进一步了解相关信息。
您会注意到我将微服务称为(微)服务。这是一种非常慎重的方式,可能会引起一些争议。微服务通常与某些技术(如 Docker)和轻量级应用容器(如 Tomcat)相关联,但在我看来,如果要成为微服务的纯粹主义者,那么(与 SOA 一样)您需要思考设计模式和原则 — 而不是技术。根据这个观点,除非您幸运地在一家非常开明的服务组织工作,否则一些约束会迫使您做出一些务实的决策。一家在 WebLogic 许可上进行了大量投资的企业不太可能放弃已有投资 — 但这并不意味着您不能采用微服务方案,当然您需要降低在此架构中使用 WebLogic 所带来的风险。其次,注册表的概念并不是微服务所特有的;事实上,举例来说,有一些解决方案就是源于大数据/Hadoop 等解决方案。
Gartner 已经开始谈论微型应用或微应用,颇具微服务的意味,这在一定程度上也是对我观点的支持。其本质是用更加切实可行的方式来应用微服务原则 — 并不是每家企业都像 Netflix 和 Uber 等微服务的典范企业那样需要超强的可扩展性和弹性。但是我们都需要能够轻松管理服务寻址。
要理解注册表的作用,我们需要回过头来先了解一下微服务背后的一些概念。我们先来回顾一下:
仅从这些角度来看,我们首先需要知道服务实例的位置 — 我们需要通过隐含或明确的方式了解实例的数量,以便了解可用容量。除此之外,还需要一个负载平衡器。务必要记住,由于微服务是独立部署的,因此它们可能并不会在负载平衡器可以看到的每个服务器的同一端口上运行。尽管您可以采用这种部署方式,但您实际上可以将所有服务视为一个整体。稍后我们会再回来讨论负载平衡器和路由的问题。
顾名思义,注册表的作用就是记录已有服务和服务的位置。当每个新的微服务启动时,它的一个初始操作都是向注册表声明自己的状态。之后,每个服务都需要与注册表协同工作,确保在该服务关闭或意外死机时,注册表都能及时知晓。

这就产生了两个问题:
我们最不希望遇到的就是注册表的单点故障,因为这会破坏我们一直以来孜孜以求的目标。所幸的是,所有可用的重要注册表都支持某种形式的信息协作和共享。一些常用策略得到了多种不同注册表实施的采用,这包括:
第二个问题可以用具有预定义地址列表(在理想情况下,基于 DNS 或虚拟 IP)的微服务来解决;微服务会检查该列表,尝试联系注册表,直到获得响应。这种查找节点进行协调的模式是相当常见的 — 例如,在集群中运行的 ActiveMQ 消息代理也采用这种操作方式。发起通信的最后一种方案是使用网络广播。这种方式不太有吸引力,因为许多服务在启动时会产生大量的网络流量,但是一些 CORBA 代理过去采用这种方式。
我们现在已经知道如何在注册表中注册并让其知晓我们的存在。但这只解决了一半的问题。实际上我们需要了解如何利用这些信息,确保所有负载分布在所有实例上,网络基础设施可以将负载路由至微服务实际所在的位置。使用注册表的两种核心模式如下:

然后,客户端可以将引用缓存一段时间。当然,这意味着实例之间的负载平衡可能是有问题的,仅引入新服务实例并不会立即传播负载。这种模式的优势在于,在全球分布的场景中,您有可能会找到最近的即时微服务实例,而无需任何 DNS 操作。采用 Eureka 框架的 Netflix 就支持这种模式。

这种服务器端方案在许多方面反映了微服务的真意:只做一件事,把它做好。负载平衡器负责平衡负载,注册表只管理注册表,微服务并不关心其请求由谁处理 — 无论是其他微服务还是单体系统。这是以性能下降为代价的,并且实现效果在某种程度上取决于具体的产品(例如 NetScaler 和 F5 BigIP)。
如果您是从零开始,不需要处理原有的单体系统,或者希望在应用域中而不是在网络基础设施中进行路由管理,那么客户端模型是理想之选。如果您要将微服务与其他元素(可能是单体系统)混合使用,或者希望利用 DNS 等网络基础设施元素来优化路由,您可以考虑使用服务器端模式,因为在这种模式中,DNS 和网络路由可以隐藏差异。替代方案是建立一个代理组件来注册单体系统的端点并假装单体系统的心跳。如下图所示。

客户端模式:需要将平衡与网关相结合,这意味着 SkyDNS 和 Eureka 等解决方案已经成为有效的 API 负载平衡器(为区别于与下一代方案,我们将其称为第一代)。
到目前为止,我们实际上只是考虑了一个严格受控或封闭的微服务生态系统 — 换句话说,这是一个不需要关注访问控制、限制、安全性、收益等问题的环境。一旦开始考虑这些问题,那就需要引入防火墙,最好是引入 API 网关。
如果您采用包含 API 网关的客户端注册表模式,那么您需要非常仔细地了解该网关的布置方式,否则服务很容易忽略或绕过该网关。这意味着网关在执行洞察和控制方面的优势可能会丢失,如下图所示。

使用服务器端注册表就比较简单,因为只需要将网关放在负载平衡器旁边,如下图所示。

这就引出了我们所说的第二代 API 负载平衡器。这种方法的理念不仅是将负载平衡与注册表合并为单一组件,而且还整合了网关特性。这不同于网络基础设施解决方案的发展历程,网络基础设施解决方案之前一直是选择防火墙或者负载平衡器,但现在是一种复合解决方案。
这种方式消除了注册表、负载平衡器与网关之间的通信开销,并且微服务环境变得非常简单。
实际上,刚才介绍的第二代 API 负载平衡器实际上可以作为本文开头提及的 Luis Weir 的文章中所述的第三代 API 管理解决方案的一部分。

可以用两个论断来挑战这种方案:
除非解决方案成为组织的核心 IP ,或者有人在市场上推出重型杀手级产品/开源框架,否则 NetScaler 和 F5 工具包的优化不太可能被超越。但是我们可以通过在几个方面消除大量开销来取胜。请考虑以下节省:
说到吞吐量,其潜在成本不可忽略,但如果网关功能是策略驱动的,成本仅与策略复杂性正相关,如果我们可以将外部调用 API 与内部调用 API 的策略相分离,那么可以将负载定制为在其中一侧具有更高的安全敏感度。
问题是,如果第二代 API 负载平衡器是一个优秀的方案,那么它为什么还没有得到应用呢?我们的回答是网关还不够成熟 — 一些网关解决方案正在向轻量级 ESB 转变(就其当前状态来说,我同意之前的论断),它们在 ThoughtWorks 技术雷达上所处的位置就可以反映这一点。但是,我们可以看到这种需求是未来的发展方向 — 请考虑 Feign 让 API 对注册表可见的简化机制。随着我们向第四代 API(即万物皆可为 API)发展,那时 API 将无处不在,对第二代 API 的需求也会不断增长。从另一个角度来看,第三代 API 管理中已经纳入了负载平衡。
在 Oracle PaaS 生态系统中,API 平台云服务仍然很年轻,因此所提供的只是反映关键需求的功能。但是可以通过 SDK 对其进行扩展来提供更多功能,而且 API 平台的网关引擎部分是高度可扩展的,其部分基础源于电信市场,因此具备与生俱来的高性能。Oracle 应用容器云当前在其平台中使用第一代 API 负载平衡器;如果它未来采用第二代模式,我一点也不会感到惊讶。此处另一种可能是,如果客户同时采用两种产品,那么 ACCS 会转而使用支持负载平衡功能的 API 平台 CS。
Oracle ACE Associate Phil Wilkins 是 Capgemini 的高级顾问,主要负责 iPaaS、中间件和 Oracle 技术。他与人合著了《实施 Oracle 集成云服务》(2017 年,Packt),并且经常为 OTN、UKOUG Oracle Scene 和其他一些刊物撰写文章。