REST 会是 SOA 的未来吗?

阅读数:10827 2011 年 12 月 20 日 00:00

好像无论我们到哪儿都能听到这样的说法:REST 将会是 SOA 的未来。很多刊物也将 REST 和 SOAP 与 WS* [1] 标准进行比较,但这些比较看起来都太过简单了。近来出现了两种较为主流的方法——本真 REST(true REST)以及将 REST 作为面向服务的技术方法(又称 REST Web 服务 [2])。本文讨论的重点为:是否其中一种方法能够改进 SOA 实现。

面向 SOA 的本真 REST

本真 REST 当然是对面向资源架构的一种实现,而并非一种纯粹的技术决策。所以当讨论本真 REST 时,真正应该讨论的问题是:其基础支撑——面向资源的架构(ROA)——是否真的适合作为你的 SOA 实现。

为正确评估该问题,让我们首先回想一下 SOA 的架构风格,它是基于企业业务架构的功能性分解,并且引入了两个高层次的抽象:企业业务服务和业务流程。企业业务服务代表的是现有 IT 能力(和企业的业务功能相一致)。业务流程编排业务服务,并定义业务的整体功能。

而 REST 是一组被称之为面向资源架构(ROA)的架构准则。ROA 构建在资源这一概念之上;每个资源都是一个能够直接访问的分布式组件, 可通过一个标准的、通用的接口来处理。所以,面向资源的架构(ROA)其最根本的还是一种基于资源的分解 [3]

为了评估本真 REST 是否适用于面向 SOA 的实现,我们真正需要回答的问题是,“服务和资源之间到底是什么关系?”

服务 vs. 资源

何为服务?

在最简单的情况下,服务可以被定义为一个自包含、独立开发、可部署、可管理和可维护的软件实现,它从整体上为企业提供特定的与业务相关的功能,并且在设计上是“可集成的”。“服务”可以通过动词(verb)来定义(例如,“验证客户信用积分”,这描述了服务实现的业务功能)。

服务并不是某个编程结构或一组 APIs,而是一个用于实现企业解决方案的架构(设计单元、实现以及维护)和部署构件。服务接口(尤其对某个给定的服务而言)定义服务功能,并且可由多种方式实现。存在两种基本的定义服务接口的方法——RPC 风格和消息(messaging)风格,RPC 风格实现使用服务调用语义并且通过服务接口中的一组参数来定义。而消息风格的服务接口被有效地固定(本质上只需要进行“执行”操作)使用 XML 文档作为输入和输出(这和 GoF 设计模式非常相似)。在这种情况下,服务语义是由输入和输出消息的语义来确定 [4]

过去,服务通常被定义为一组方法的集合,但正如参考文献 [2]中解释的那样,这些方法彼此相互独立 [5],但作为整体它们共享同一个命名空间,这样简化了对服务的管理。

何为资源?

在最简单的情况下,资源可以被定义为一个可直接访问的、独立开发的、可部署的、可管理的和可维护的软件构件,它支持特定的数据。资源可以通过名词(noun)来定义,比如“医生的预约”就描述了资源提供的数据。某一资源也可以和其他资源相关联并为它们提供引用(链接)。实际上,一个资源就类似于一个对象 [6],不过它是带有预定义(CRUD)接口语义的对象。

REST 中的语义基于 HTTP 操作集,如下所示 [5]

  • createResource——创建一个新的资源(以及相应的唯一标示)– PUT
  • getResourceRepresentation——获取资源信息– GET
  • deleteResource ——删除资源(可选地包括相关联的资源)– DELETE(只是引用的资源),POST(当需要删除相关联的资源时使用)
  • modifyResource——更改资源— POST
  • getMetaInforatmion——取得资源元数据信息—HEAD

资源通过两部分定义:资源 URL 和资源所提供的所有操作上定义的输入 / 输出参数 [7]。这和服务不同,服务的方法之间是完全独立,并且能够以独立端点(endpoints)的方式部署,而资源上的方法遵循 OO 语义,这意味着所有的方法(除createResource以外)都必须依附于底层的某个资源(同一个 URL)。

资源和服务之间的根本差异

基于上述对资源和服务的定义,凭直觉它们显然是不同的。我们先继续深究这些差别,然后再讨论它们是如何对最终架构产生影响的。

正如文献 [6]中描述的:

REST 不仅不是面向服务的,相反,面向服务和 REST 风马牛不相及

文献 [7]中进一步阐明了二者之间的区别:

如果把 WS-* 比作是互联网世界的 RPC,那么 REST 就是互联网世界的数据库管理系统(DBMS)……传统的基于 SOA 的集成表现了不同软件构件之间通过各种过程或方法进行交互。REST 有效地将每个软件构件看作一组数据库表,而这些构件之间使用 SELECT, INSERT, UPDATE 和 DELETE 来通信。(或如你所想的使用 GET, PUT, POST, DELETE)。那业务逻辑放在哪里呢?在存储过程中?不太对,其实在触发器中。

这里我们用 J2EE 打个稍微不太恰当的比方。我们把服务想象成无状态会话 bean,而资源想象成实体 bean。

服务 (或会话 beans) 作为控制器控制执行所需的操作,不管底层是哪个资源。打个比方,某个支出账户服务可能会用到账户 ID、支出金额和支出所需账户。这样的服务可以支出任何现有账户。

资源(或实体 bean)充当数据访问机制,其面对给定数据类型的某一实例。比如,为了从某一账户支出,需要先找到这一账户相关的信息,然后才能更新它,从而向所需账户进行支出。另外提醒一下,与能实现任意所需的方法的实体 bean 不同的是,一个 REST 资源只有一个更改资源的方法。这意味着真实的业务操作——支出——只能编码成消息请求的一部分。

区别引出的结论

综上所述,不可能使用本真 REST 来构建 SOA 系统。构建系统可以,但一定不是 SOA。两者都可以从与业务一致的分解入手,但是由于各自使用截然不同的分解方法,它们最终得到的也是基于不同组件和连接器的完全不同的架构风格 [8]

仅仅因为它们都试图解决同一个问题——业务与 IT 对齐,并且都基于业务驱动的分解,并不能表明最终的架构风格也是一样的。

另一个问题在于能否可能使用本真 REST 来构建一个完整的系统。鉴于上述理由,这个问题等价于能否可能只使用数据库或实体 bean 来构建一个完整的系统。当然你可以了,但是需要以存储过程(重写方法的本意)的方式增加处理代码,或者触发器(完成基于数据变化的后置处理)。这同样适用于本真 REST 实现—你只有通过改变 modifyResource 方法的本意(通常使用命令行模式)来实现不止数据更新这个方法。

因此,某个基于 REST 的实现和本真 REST 是大相径庭的;一般来说其包含了至少一些 REST Web 服务的元素。那么 REST Web 服务是什么呢?

REST Web 服务

REST Web 服务方法是指单纯使用 REST 技术作为通信手段来构建 SOA 的一种方法。在这种情况下,服务由 SOA 风格的分解来定义,而基于 REST 的 Web 服务 [9]作为通信。

虽然一般也被称为 REST,这种方法其实和本真 REST 没有一点关系,倒是和 POX(plain old XML over HTTP)很类似,不过与 POX 不同的是,它不仅支持 XML,还支持其他数据类型,比如 JSON(JavaScript Object Notation)、ATOM、二进制数据块。而且,它不像 POX 那样通常只基于 GET 和 PUT,它基于更多的 HTTP 方法。

归功于 Web 的优势和 Ajax 技术的遍地开花,使用 JSON 逐渐变成主流的方法;大部分流行的浏览器都内置对 JSON 支持。由于在 JavaScript 中处理 XML(尤其是带有很多命名空间)并不是一件容易的事,所以,Web 实现使用基于 JSON 的 REST Web 服务要容易的多。面向 Web 交互的 REST Web 服务的扩增导致了这些技术的日益流行和广泛传播。

真正的差异是什么?

描述 SOAP 和 REST 区别的出版刊物通常会指出如下 REST Web 服务的优点,比如 [11]

  • 轻量级——无需太多额外的 XML 标记
  • 人工可读的结果集
  • 易于构建——无需工具支持

虽然这些区别很重要(我随后会再详细讨论),但是 SOAP 和 REST 最主要的区别在于 REST 是直接实现于 HTTP 协议之上,而 SOAP 引人了一个抽象层(SOAP 消息传递),这可以在任何传输协议之上实现。标准化 SOAP 绑定目前存在于 HTTP、SMTP 和 JMS 之上,而非标准化绑定已经在其他一些协议解决方案实现了。这层额外的抽象层(提供协议和基于 SOAP 实现之间的解耦)是造成 SOAP 和 REST Web 服务区别的根源。

对于这一抽象层的看法很大程度上取决于不同的人。REST 阵营认为它是过度设计的产物,并声称没有提供任何实际价值。他们声称 HTTP 已经提供了服务交互实现必需的所有特点。而 SOAP 阵营,从另一方面,争辩道 HTTP 并不是服务交互(尤其在企业内部)通常所需的唯一协议,而设计一个方便的、可扩展 [10]的抽象层对构建健壮的、功能丰富的服务交互是很有必要的。

虽然两种观点都有其可取之处,但我认为把 SOA 实现限制到单一协议,即 HTTP,实际操作起来不太可行。诚然,HTTP 是无处不在,并且其使用方法一般也无需投资额外的基础设施,但是 HTTP 是不可靠的(HTTP-R 没有广泛被采用)、同步的(产生了瞬时的耦合) [11]、而且也没有事务语义等等。

再者,就算认为 HTTP 是在实现中使用的唯一协议,也可以非常方便的利用 SOAP 信封把业务信息(SOAP 消息体)和基础设施信息或附加信息(SOAP 消息头)从 SOAP 消息中隔离。总的来说,如果你本来的实现并不需要任何基础设施或附加数据,整个 SOAP 信封的开销是很少的——只需两个标签,而且对必要时添加数据提供了明确定义的方法。

所以,从各个方面来看,以数据信封的方式将业务信息和基础设施关注分离是很强大的模式,甚至 REST Web 服务实现也常常使用这种方法。至于是否使用标准的 SOAP 还是定制化信封 [12]模式要根据具体实现而定。

其他关键不同点

我们花点时间来讨论一下其他一些常常被发表刊物引用的关于 SOAP 和 REST Web 服务的不同点。

简单化

一个普遍的观点是 REST 要比 SOAP 简单得多。照这个观点,REST 简单的根源基于一个事实:REST 不需要 WSDL 或任何接口定义。至少可以认为这种论调有点天真。无论哪种用于服务消费者和提供者之间通信的技术,都必须在语法和其消息交互(接口) [13]的语义上达成一致。这意味着就 REST 而言,下面两个方法有一个是可能的:

  • 以文本方式定义一个接口,并基于接口文档描述中的通用接口定义来“手工地”编写数据的编码 / 解码。虽然这种方法常被 REST 拥趸所推崇,其接口包含的元素很少超过 10 到 15 个,但这不是典型的粗粒度 REST 服务。而且,这种方法很容易出错,所以,大部分可行的 REST 框架都遗弃该方法而使用下面的方法。
  • 在 XSD 的层次定义接口,基于流行框架(比如,面向 XML 的 JAXB 或 Castor,面向 JSON 负载的 Jackson)产生数据的编码 / 解码。这种方法效果上就是 WSDL 的简约版,并且需要的工作量和基于 SOAP 实现差不多一样。事实上,完全相同的方法经常被用于基于 SOAP 的实现,设计一个单独接口和服务执行的命令模式。WSDL2.0 和 / 或 WADL for REST 就是对该方法的扩展。

另一个 SOAP 常常被抱怨的就是复杂的 WS* 标准集。虽然不存在一个单独的规范来罗列这些关键的 WS* 标准集以及其彼此的关系,但对大部分服务交互用例还是存在一个标准的。就算如此,选择一个适当的 WS* 标准和其用法可能也需要一些额外理解和实现时间,但是:

在 REST 和 SOA 之战中争论简单化还是标准化是荒唐的,因为没有标准支持的简单只能有害于成本和应用的可管理性。

所以,除了那些简单到极点的例子之外,如“温度转换器”,REST 并不比 SOAP 简单多少。

轻量级

另一个众多 REST 拥趸宣扬 REST 是 SOAP 的一种取代的原因是,实际上的 REST 请求和响应消息都较短。这主要基于两个原因:

  • SOAP 需要一层 XML 包装器来包装所有的请求和响应消息,这会增加消息的大小。这话没错,但重点不是包装器增加了多少字节,而是它创建在整个负载中的比例。因为包装器的大小是固定的,其所占比例随着消息的不断变大而变小,最终可以忽略不计。考虑到一般服务都是相当粗粒度的,请求和回复消息的大小也是相当大的,所以 SOAP 信封的负载不太会成为大问题。
  • SOAP 是基于 XML 的消息传输,而 XML 使用冗余的编码。REST,在这方面,提供了更轻量级的消息传输替代方案——JSON [14]。这话也对,但利用消息传输优化机制(MTOM),大部分 SOAP 框架都支持,可以把消息拆分成多个小的基于 XML 的 SOAP 信封 / 头 / 体部分,而附加的包含消息内容的部分可以编码为任何 MIME 类型,包括 JSON 和二进制流等。

虽然理论上讲,REST 要比 SOAP 轻量级,但实际上,利用一些高级 SOAP 设计技术,真正使用中的 SOAP 和 REST 消息大小的差别是很小的。

易于构建 – 无需工具支持

因为 REST 基于 HTTP,其拥趸认为,我们可以使用熟稔的技术,比如 Java servlet API 和 Java HTTP 支持来编写 REST 服务的实现端和客户端,而无需任何特定工具的帮助。这可以说是对的,但前提是你想要“手工”实现构建输入 / 输出消息和数据编组。SOAP Web 服务也可以实现同样的工作。然而,大家很少希望编写这种样例代码,结果还是会使用工具,SOAP 和 REST 都是。

结论

REST 既适用于使用 ROA(本真 REST 方法)的系统设计,也适用于使用 REST 技术(REST Web 服务)的 SOA 设计实现。虽然两种方法都有其优势,但都没有改变最难的部分——定义和企业业务模型一致的业务服务 / 资源。有些情况的确两种都适合,但归根到底这完全是两种不同的风格。

关于作者

Boris Lublinsky是 NAVTEQ 公司的首席架构师,在这家公司中他的工作是为大型数据管理及处理、SOA 定义架构愿景,并且实施各种 NAVTEQ 的项目。他还是 InfoQ 的 SOA 编辑, OASIS 的 SOA RA 工作组的参与者。Boris 是一位作者,还经常发表演讲,他最新的一本书是《Applied SOA》

致谢

我要谢谢我 NAVTEQ 的同事,尤其是 Jeffrey Herr 在我撰写这篇文章时提供的帮助。也要感谢 Stefan Tilkov 和 Kevin T. Smith 提供的有趣反馈(多数是负面的),这些反馈有助于文章的改进。

参考

  1. Cesare Pautasso,Olaf Zimmermann,Frank Leymann 著《RESTful Web Services vs. “Big” Web Services: Making the Right Architectural Decision》
  2. Boris Lublinsky 著《 Defining SOA as an architectural style
  3.  面向资源的架构
  4. Martin Fowler Richardson 著《 Maturity Model: steps toward the glory of REST
  5. 面向资源的架构与REST
  6. Dhananjay Nene 的博文“ Service oriented REST architecture is an oxymoron
  7. Dhananjay Nene,“ REST is the DBMS of the Internet ”。
  8. Dhananjay Nene,“ Musings on REST
  9. J?rgen Thelin,“ A Comparison of Service-oriented, Resource-oriented, and Object-oriented Architecture Styles
  10. Richard Hubert 著《Convergent Architecture: Building Model Driven J2EE Systems with UML》,Wiley,2011,ISBN:0471105600
  11. Arun Gandhi, “ SOAP vs. REST – The Best WebService ”。
  12. 请参见链接
  13. Lawrence Mandel,“ Describe REST Web services with WSDL 2.0
  14. Web 应用描述语言
  15. Stefan Tilkov 访谈 Sanjiva Weerawarana,“ Debunking REST/WS-* Myths
  16. Lori MacVittie,“ SOAP vs REST: The war between simplicity and standards
  17. 请参见链接
  18. Mark Little,“ A Comparison of JAX-RS Implementations ”。

[1] 看这里,文中有个很好的比喻。

[2] 这里我使用的这个词语,从技术上其毫无意义,也不是指 REST,但在业界被广泛使用,而有很多人也认为它就是 REST。

[3] 按照定义,资源可以是任何应该被直接呈现和访问的组件。

[4] 这类服务常用的一种实现是基于“命令模式”。一个输入文档定义命令本身和用于执行命令的数据。

[5] 方法独立源自于这样一个事实:不同的方法可以执行同一数据——这里指的是无论是否被服务暴露都存在的企业数据,而不是在 OO 中的针对特定数据的某对象实例。

[6] 例如,在文献 [4] 中对 OO 和 REST 做了直接类比。

[7] 许多 REST 倡导者声称后者是没有必要的。我们在文章后面会再回到这个问题上。

[8] 架构风格就像面向于不同软件系统之间结构和连接的“设计模式”。文献 [10] 提供了关于架构风格的一个比较完整的定义,“架构风格是指一组有相同原则和属性的架构”

[9] 另一个在业界被普遍乱用的名称——根据定义,Web 服务就是 SOAP 消息。

[10] 所有的 WS* 实现都重度依赖 SOAP,尤其是 SOAP 头。

[11] 你总是可以在 HTTP 上实现异步消息机制,但是需要额外的抽象层,比如 SOAP 就在其上使用了 WS-Addressing。

[12] 许多 REST 倡导者认为 HTTP 已经有了一组标准的消息头,因此 SOAP 消息头完全没有必要。这里的问题在于一组预定义好的 HTTP 头固然有其良好定义的语义,但任何应用特定数据必需一个自定义 HTTP 消息头,这和自定义 SOAP 消息头的复杂度相同。

[13] 一个有趣例子是,在很多 JAX-RS 实现中客户端 API,其接口往往是一个 java 接口——许多对多语言的支持。

[14] 简单通常意味着高价——所以,要试图通过无需手动编码对象类型而用 JSON 消息实现多态

查看英文原文: Is REST the future for SOA?


感谢马国耀对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

收藏

评论

微博

用户头像
发表评论

注册/登录 InfoQ 发表评论