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?