REST会是SOA的未来吗?
好像无论我们到哪儿都能听到这样的说法: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)接口语义的对象。
- createResource——创建一个新的资源(以及相应的唯一标示)– PUT
- getResourceRepresentation——获取资源信息– GET
- deleteResource ——删除资源(可选地包括相关联的资源)– DELETE(只是引用的资源),POST(当需要删除相关联的资源时使用)
- modifyResource——更改资源— POST
- getMetaInforatmion——取得资源元数据信息—HEAD
资源通过两部分定义:资源 URL 和资源所提供的所有操作上定义的输入/输出参数[7]。这和服务不同,服务的方法之间是完全独立,并且能够以独立端点(endpoints)的方式部署,而资源上的方法遵循 OO 语义,这意味着所有的方法(除createResource以外)都必须依附于底层的某个资源(同一个 URL)。
资源和服务之间的根本差异
基于上述对资源和服务的定义,凭直觉它们显然是不同的。我们先继续深究这些差别,然后再讨论它们是如何对最终架构产生影响的。
REST 不仅不是面向服务的,相反,面向服务和 REST 风马牛不相及
如果把 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 提供的有趣反馈(多数是负面的),这些反馈有助于文章的改进。
参考
- Cesare Pautasso,Olaf Zimmermann,Frank Leymann 著《RESTful Web Services vs. “Big” Web Services: Making the Right Architectural Decision》。
- Boris Lublinsky 著《Defining SOA as an architectural style》
- 面向资源的架构
- Martin Fowler Richardson 著《Maturity Model: steps toward the glory of REST》
- 面向资源的架构与 REST
- Dhananjay Nene 的博文“Service oriented REST architecture is an oxymoron”
- Dhananjay Nene,“REST is the DBMS of the Internet ”。
- Dhananjay Nene,“Musings on REST”
- J?rgen Thelin,“A Comparison of Service-oriented, Resource-oriented, and Object-oriented Architecture Styles”
- Richard Hubert 著《Convergent Architecture: Building Model Driven J2EE Systems with UML》,Wiley,2011,ISBN:0471105600
- Arun Gandhi, “SOAP vs. REST – The Best WebService”。
- 请参见链接
- Lawrence Mandel,“Describe REST Web services with WSDL 2.0 ”
- Web 应用描述语言
- Stefan Tilkov 访谈 Sanjiva Weerawarana,“Debunking REST/WS-* Myths”
- Lori MacVittie,“SOAP vs REST: The war between simplicity and standards”
- 请参见链接
- Mark Little,“A Comparison of JAX-RS Implementations”。
说明
[2]这里我使用的这个词语,从技术上其毫无意义,也不是指 REST,但在业界被广泛使用,而有很多人也认为它就是 REST。
[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?