本文关键点
在过去的几年中,软件开发社区中出现了越来越多的反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范式的基础。
脚注
本文的目的不是讨论REST的定义。术语“REST”将用于指代Fielding的原始定义以及HTTP上的CRUD风格的API。
有关REST/gRPC/GraphQL如何根据上下文决策的实际分析,请阅读Phil Sturgeon的这篇博客。
…而且,在很早的时候,就已经不再满足于将REST只是概括为HTTP上的CRUD了。请参阅这里。
回到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