替換Rest?不,軟件工程應該構建成熟的REST生態

本文關鍵點:

  • 在過去的幾年中,軟件開發社區中出現了越來越多的反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服務繁榮的高峯時期。

英語原文:

https://www.infoq.com/articles/overcoming-restlessness

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章