持续演进,克服“REST 缺乏”

阅读数:4479 2019 年 3 月 7 日

本文关键点

  • 在过去的几年中,软件开发社区中出现了越来越多的反 REST 观点。然而,替代技术经常出现在特定的上下文中,它们呈现出优点和缺点往往与特定用例相关。

  • REST 崛起本身就是由一种错误的二分法导致的,当时 SOAP 扮演了反面角色。SOAP 试图提供一种通过 Web 协议打通隧道的方法,而 REST 方法则拥抱了这种方法。

  • 软件工程行业不应该寻求替代 REST,而应该在开发新协议技术优势的同时构建成熟的 REST 生态,从而谋求更进一步的发展。

新的 API 协议(如 GraphQL、gRPC 和 Apache Kafka),作为受 REST 启发的 HTTP API 的替代品,越来越受到欢迎。本文认为在一对一协议中体现不出 REST 范式的优势。软件工程行业不应该寻求替代 REST,而应该在开发新协议技术优势的同时构建成熟的 REST 生态,从而谋求更进一步的发展。

关于协议、范式和错误的二分法……

温哥华人 Tim Bray 最近的博客文章“后 REST ”引起了业界的广泛关注,这是有原因的。随着 Web API 得到越来越多的应用,人们开始怀疑 REST1 是否是 Web API 的理想通信约定。除了开放 Web 通信最初的范围之外,REST 现在还用于提供 Web 应用程序数据、提供微服务间通信、促进基础设施管理和自动化,甚至还用于消息传递、事件分发和流等异步模式。

Tim 的文章很好地概括了 REST 的用法、它的局限性、一些新兴的替代协议 (GraphQL 和 gRPC),并推测了 Web API 通信的未来。虽然我大致上也赞同这篇文章的观点,但我觉得这个话题不应仅限于这些,还有更多内容要谈。换句话说,我不只是想看看什么可以替代 REST,更希望我们考虑一下如何将 REST 的优势与这些新协议的创新结合起来,从而为分布式软件生态系统中的通信提供不断演进的替代方案。

新的协议,旧的战线,错误的二分法

在过去的几年中,软件开发社区中出现了越来越多的反 REST 观点。许多文章都指着 REST 的局限性大发牢骚,并提出了替代的通信协议或方法。

在支持 GraphQL gRPC 异步通信的声音中,甚至更模糊的观点中,经常看到“REST 在 x 上不好,所以使用 y 代替”的说法。这些争论差不多是这样说的:

  • GraphQL 比 REST 更好,因为它能够让 API 消费者控制接收到的数据,并能让 API 提供者在服务器端聚合资源

  • gRPC(加上协议缓冲区) 比 REST 更好,因为它是类型安全的,它通过二进制序列化优化了性能,并且能够利用 HTTP/2 的能力

  • 异步的通信 (AMQP、Kafka 等) 优于同步的 REST 通信,因为它减少了阻塞和线程使用,从而提高了服务的自治

这些方法都是在特定的上下文中产生的。GraphQL 是由Facebook 创建的,在他们重新开发Facebook 移动应用程序时,它也是其中的一部分。它是与 Relay React 原生JavaScript 框架一起使用的在线通信方法,本质上,这一方法是为应用程序提供特定的数据。许多 GraphQL 的公开支持者都倾向于数据中心和 JavaScript,这一点大家都能想到。gRPC 和协议缓冲区本来是谷歌内部使用的,并遵循与 Kubernetes 容器编制项目类似的公开路径。许多的 gRPC 倡导者都集中在基于容器的应用程序之间的通信上,这一点大家也都能想到。互斥异步通信通常用于响应式系统或事件源的上下文中。在这些特定的上下文中,专门为其设计的方法自然会比那些更通用的 REST 方法具备一些优势,这是件很自然而然的事。

为了捍卫 REST,我们很容易流于表面去看待这些批评,并提出如下的观点:

  • 对于 GraphQL 案例,REST 范式中完全没有限制用户选择或资源聚合 (在单个资源上使用静态接口只是一种常见的实践),而且大量信息表明,就算限制用户选择也有其自身的好处

  • 对于 gRPC,运行时优化不太可能是大多数分布式体系结构中的主要瓶颈,而 gRPC 的对嵌入类库的需求(更不用说 protobuf 的枚举结构)可能会导致无法预见的问题

  • 对于异步,绝对有必要包括基于事件的场景,但是这些场景很可能是除同步模式 (如查询和命令) 之外额外的

然而,在我看来,这些反面意见并不能说明一切。软件工程是一个还缺乏 REST 的行业,我们经常过度简化我们的问题,以证明过于简单的解决方案是合理的。我们喜欢给“当红的平台”贴上标签,以激励大家迅速跳到一些新的安全地带。因为批处理不好,所以实时处理就是好的。因为整体系统不好,所以微服务就是好的。在特定上下文中使用 REST,它就变成了个反面典型,这就像上面的论调一样,其实就是非好即坏的错误的二分法。也许我们应该研究研究另一个问题:REST 是如何成为用于分布式计算中组件到组件网络跳转的默认通信方法的? 让我们穿越回最开始的时候。

REST 的起源、兴起和流行

Roy Fielding 在 2000 年博士论文“架构风格与基于网络的软件架构的设计”中有一章定义了 REST(表述性状态转移)。本篇论文的主要目的是“定义一个理解软件架构的框架”……,以指导基于网络的应用软件的架构设计。在架构风格示例中,REST 就包含其中,这些架构风格将万维网的设计原则编写成代码,重点强调了接口的可演化性、可伸缩性和通用性。与上文列出的新方法的上下文相比,REST 一开始的问题领域有着非常广阔的空间。

在这广阔的空间之中,其中一个想法非常流行,那就是在浏览器之外基于网络共享数据和服务。软件开发人员快速基于Fielding 的工作成果并将其付诸实践 3。REST 崛起本身就是由一种错误的二分法导致的,在当时SOAP 扮演了反面角色。SOAP 试图提供一种通过Web 协议打通隧道的方法,而REST 方法则拥抱了这种方法。“ REST 是 Web 的一部分,而不仅仅是在 Web 上”,对于已经在构建基于 Web 的解决方案的软件工程师来说,这一概念他们从直觉上更愿意直接去选择它。

随着 SOAP 和 WS-* 生态环境变得越来越复杂,由于 REST 的相对简单性和可用性,使其胜出了。随着时间的推移,JSON 出于类似的原因取代了 XML,成为 Web API 事实上的数据格式。随着 Web 计算范式的使用扩展到新的场景(比如企业应用程序集成、云供应、数据仓库查询、物联网等等),REST API 采用的范围也随之扩展。

现在,如果针对每个特定的使用场景审视一翻,可能 REST 的适用性会存在一些弱点,或者会有一些看起来更理想的替代通信方法。但这么比较就忽视了 REST 所具备的广泛性能力。由于 REST 的广泛性,已经惯于使用 AJAX 调用的 Web 开发人员可以凭直觉掌握如何使用 AWS 的 API 来提供云基础设施;基于 Web 的社交网络的开发人员可以迅速为移动应用程序铺设管道;企业级软件的开发人员所能做到的大家就更为熟悉了,他们可以使新拆分的微服务相互通信。软件工程是这样一个领域:交付障碍往往是人为造成的,而不是机器。充分理解方法提供的价值,通常比技术最优化的利基解决方案对交付时间有更大的影响。

在 REST 生态系统中,这种广泛性还带来了健壮性。Swagger(现在是 OpenAPI )作为元数据规范适时出现,成为一个有机的补充,它旨在帮助开发人员记录、设计和使用 API。OAuth 为身份验证和授权提供了一个可伸缩的、可转换的框架。“API 管理”作为一组特性出现,包括速率限制、动态路由、缓存等,实践证明这些在提供 REST API 时非常有用。REST 范式的全面性及其生态系统的成熟度表现出 REST 作为软件系统中基于网络的通信方法的最大价值。很可能,这种广泛性更多地来自于 REST 成为“Web 工作的方式”,而不是任何一个技术细节。

后 Web 范式中的通信

Web 对软件工程的影响再怎么强调都不为过。在 REST 兴起的同时,软件工程领域也涌现出了开源、敏捷、DevOps、领域驱动设计和微服务体系架构。这些运动中的每一个都得益于 Web,它们不约而同地放大了软件交付中人为因素的重要性。随着云计算提供的灵活性和方便性,已经涌现出一种新的软件工程范式,它的特征是持续运行、持续发展、松耦合的应用程序和服务。虽然 Tim Bray 将他的文章称为“后 -REST”,但也许这种新范式可以称为“后 -Web”。由于这种范式的特征与 Fielding 的 REST 的原始原则是一致的,因此舍弃 REST 从头开始是没有意义的。换句话说,忽视 20 年来的技术创新同样是个很幼稚的做法。

那么 REST 的价值在这个新范式中如何演变呢? 现在,越来越多的组织采用“API 为上”的方法进行软件开发,也就是说,强调在应用程序和服务中机器接口的设计与 UI 的设计同样重要,并应借助这些 API 来解耦负责不同领域的团队的开发工作。OpenAPI 通常在这种方法中扮演重要角色,因为它是与实现无关的接口规范。根据后 -Web 范式,这对构建或修改软件系统的各方面人员都有好处。目前已经有一个正在进行的项目,它是来自 Fran Mendez AsyncAPI ,其旨在为基于事件的交互带来同样的价值。沿着同样的思路,Mike Amundsen 和 Leonard Richardson 引入了 ALPS 规范来记述基于网络的应用程序交互的语义。像这些成果有助于解决构建分布式系统的设计时的挑战。

在云本地运行时中也有机会扩展 REST 的价值。向微服务的迁移引入了进程间通信 (IPC) 常常发生的网络边界问题。这些物理边界可以刻意投影为业务领域边界,以实现上面讨论的人员利益。

但是,这存在一个潜在的运行时权衡,即额外的网络延迟和服务调用链中出现部分故障的可能性。

服务网格模式为基于容器的系统解决了这些问题,它的特点是有一个“边车”服务代理,由它处理应用组件之间所有基于网络的通信。服务网格拓扑意味着,已经在应用程序容器及其相关的边车之间重新引入了 IPC。尽管如此,应用程序容器的开发人员仍然需要在代码中特别指定网络协议,因为服务代理通常不会更改代理消息的传输协议。

究竟,这些应用程序开发人员应该负责协议处理吗? 它们应该处理抽象的服务请求 (查询、命令、事件),让服务代理处理协议映射、转码和传输吗?这些问题值得商榷,REST API 的通用设计时理解可以作为开始抽象的一个起点。这些只是 REST 的广泛性可以用来帮助固化后 -Web 范式的两个领域。

一个不怎么缺乏 REST 的未来

大肆炒作的技术趋势经常吹嘘它们如何用新方法取代了旧方法。在现实中,软件工程通常是层叠进行演进的。每一个新的创新都为后续的一系列创新奠定了基础。新的 API 协议 (如 GraphQL、gRPC 和 Kafka) 将取代在某些分布式场景中使用基于资源、json 编码、HTTP 传输的消息。然而,REST 在分布式系统的发展中留下的遗产不应该只是与其实现细节相关的内容,而更多的应该是令它如此无处不在的相关特征:为通用连接性提供框架、将服务消费者与提供者分离、强调可用性和可访问性。正是这些特征使得 REST(最初定义为 Web 的体系结构样式)成为软件工程的后 Web 范式的基础。

脚注

  1. 本文的目的不是讨论 REST 的定义。术语“REST”将用于指代 Fielding 的原始定义以及 HTTP 上的 CRUD 风格的 API。

  2. 有关 REST/gRPC/GraphQL 如何根据上下文决策的实际分析,请阅读 Phil Sturgeon 的这篇博客

  3. …而且,在很早的时候,就已经不再满足于将 REST 只是概括为 HTTP 上的 CRUD 了。请参阅这里

  4. 回到 SOAP 的二分法,一边是这种有机标准的开发,一边是 W3C 和 OASIS 标准的爆炸式增长,它们形成了鲜明的对比,这两个标准出现在 2000 年初 Web 服务繁荣的高峰时期。

感谢 Mike Amundsen、Erik Wilde、Irakli Nadareishvili 和 Ronnie Mitra 找到了本文中列出的“REST 的历史”资源。

关于作者

Matt McLarty是一位卓有经验的软件架构师,领导博通公司 CA 科技的 API Academy 团队。他与组织紧密合作,设计和实现创新的企业级 API 和微服务解决方案。在软件供应商和客户端的集成和实时事务处理领域,他有着广泛的工作经验。Matt 最近与人合著了 O 'Reilly 的书《微服务体系结构和微服务 API 安全》。

查看英文原文 Overcoming RESTlessness

收藏

评论

微博

发表评论

注册/登录 InfoQ 发表评论