基於場景選擇微服務的API範式:REST、GraphQL、Webhooks和gRPC

基於場景選擇微服務的API範式:REST、GraphQL、Webhooks和gRPC

可以看到,第二個URI是可解讀的,因為包含了全部所需要的信息,即,“查詢第2頁的訂單內容”。而第一個URI是依賴於上下文的,也不可解讀,因為他的含義是“查詢下一頁的訂單內容”,需要提供“當前是第幾頁”這個上下文信息才能夠進行相關查詢或者被理解。

為此,PayPal API的設計理念是易於理解和易於集成。以下這個示例摘自其官方文檔,顯示了API的一次調用如何列出一系列活動:

curl -v -X GET https://api.sandbox.paypal.com/v1/activities/activities?start_time=2012-01-01T00:00:01.000Z&end_time=2014-10-01T23:59:59.999Z&page_size=10 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer Access-Token"

在這裡,我們看到了有效的RESTful實現的印記。遵循標準的HTTP表達範式的GET方法恰如其分的完成了其檢索資源的使命。在本例中,資源被明確定義為“activities”,並允許指定時區和頁碼的查詢需求。此外,返回值是一種特定的、已知的、支持超媒體的格式。以上是一個概要性的REST介紹,也用實際的示例說明了,輕量級、無狀態的系統正是將資源交付給客戶端的過程中所需要的。

三、gRPC概述

REST基本上可被認為是較現代的一種設計風格,而gRPC則是對歷史悠久的RPC(遠程過程調用)的一種新的傳承。RPC是一種在遠程服務器上執行過程的方法,類似於在離您的工作站數英里的朋友的計算機上運行程序。RPC有其自身的優點和缺點,事實上,這些缺點(同時也是SOAP等系統固有的問題)正是REST開發和實現的關鍵。

gRPC和REST之間的一個關鍵區別是RPC定義其交互方式的協商機制。REST通過在HTTP請求中標準化的表達來定義交互,RPC的功能則是基於限定在客戶端-服務器之間的特定協議而不是由架構本身來進行定義。RPC在很大程度上讓客戶端只需要執行 (同時也只在這方面負有責任),而將大部分處理和計算工作轉移給承載資源的遠程服務器。

因此,RPC在物聯網設備和其他需要定製化通信協議的低功耗設備的解決方案中非常流行。REST經常被認為對資源要求過高,而RPC甚至可以用於極低功耗情況。

gRPC是RPC概念的進一步發展,並增加了廣泛的特性。其中最重要的特性是ProtoBufs。ProtoBufs是語言中立和平臺無關的協議,用於對數據進行序列化,這意味著所有通信可以高效地序列化以進行高效的交流。此外,通過Google的基於令牌的系統調用SSL/TLS協議,gRPC建立了非常有效和強大的身份驗證系統。最後,gRPC是開源的,這意味著系統可以被審計、迭代以及創建代碼分支等等。

白小白:

gRPC使用ProtoBufs來定義服務。ProtoBufs全稱是Protocol buffers,是由Google開發的一種靈活的、高效的、自動化的用於對結構化數據進行序列化的協議,類似於XML,但與XML相比,Protocol buffers序列化後的碼流更小、速度更快、操作更簡單。

四、gRPC案例:GoogleCloud,Bugsnag

gRPC很難直接演示,這很大程度上是因為,根據其官方文檔的表述,gRPC通常用於“計算的最後一英里”。換句話說,gRPC通常是用來驅動和促進異構服務和API之間的通信的終端系統。

儘管如此,文檔也指出,由於其可移植性,gRPC可以在移動計算場景下使用,同時也是一箇中間處理系統,用於處理來自Google Cloud Bigtable Client API,Google Cloud PubSub API,以及Google Cloud Speech API的數據。這得益於gRPC提供的標準傳輸機制和相對靈活的數據負載,可以最好地應用於大流量、主動、高頻次通信的場景。

gRPC另一個生產案例是Bugsnag。Bugsnag工程團隊發現,相比RESTful,gRPC的最初的設計過程更加流暢,當然,由於教程和最佳實踐的缺乏,“開發和測試gRPC的門檻相當高”。但總的來說,延遲改進和傳輸成本的降低使得使用gRPC的應用對於Bugsnag來說是一個巨大的成功。

白小白:

Bugsnag,應用程序實時檢測應用,是一個可以針對應用程序崩潰錯誤進行實時檢測追蹤的軟件測試利器工具;幫助查找、追蹤手機應用和網頁應用程序中出現的錯誤問題。很顯然,作為雲服務,流量、頻次都是Bugsnag需要考慮的問題。因而也更適合採用gRPC的方案。

五、GraphQL概述

GraphQL對客戶端-服務器關係的解決方案是獨一無二的,在某種程度上是對傳統的逆轉。使用GraphQL,客戶端將決定他們想要哪些數據,以何種格式以及如何取得這些數據。這是對服務器向客戶端發號施令的經典模式的逆轉,同時,GraphQL提供了大量的擴展功能。GraphQL與REST以及RPC完全不同,REST是一種體系結構,而RPC則是由客戶端和服務器定義的特定協議(並在很大程度上契約是由服務器端的資源屬性定義的)。

GraphQL的一個巨大好處,是在默認情況下,它通常只發送最小請求,而REST通常發送完整請求(即默認同時發送它擁有的所有內容)。正因為如此,GraphQL在一些特定的用例中更加適用,在這些場景中,需要更明確的數據類型定義,並且傾向於使用較小的數據包來進行傳輸。

有人說,GraphQL的好處往往被誇大了。比如,GraphQL的“無版本”的概念,就來源於廢棄舊的字段,同時用新的字段替換,這其實也是REST API在演進時所考慮的問題。但GraphQL並非是“更好的REST”或者“REST的下一步”,而是“客戶端和數據之間的新型關係”的另一種選擇。

白小白:

關於REST API的演進,應當瞭解一下REST成熟度的概念。《RESTful Web Services》的合著者Leonard Richardson提出了一個REST成熟度模型,雖然圍繞這一模型,爭論很多,Martin Fowler、Rest之父Roy Fielding、《RESTful Web Services Cookbook》作者Subbu Allamaraju都有不同的見解。但對於全面的理解REST與GraphQL的特點,還是有幫助的(關於成熟度模型的具體含義,可參考Mryqu的文章 https://dwz.cn/JaWs9yIH)。

在這一成熟度模型中的第4級,使用超媒體作為應用狀態引擎(HATEOAS);多個URI,多個HTTP方法。在資源的表達中包含了鏈接信息。客戶端可以根據鏈接來發現可以執行的動作。實際上解答了很多現有文章對於REST和GraphQL的誤解。

一般認為,REST的多端點特性需要進行API的組合以及多次HTTP請求才能完成GraphQL一次完成的查詢。也就意味著上文中所說的,當服務器端的資源發生變更,REST必須引入多版本的概念來解決,而GraphQL則只需要在查詢條件上稍作修改即可。

事實上,由於HATEOAS的存在,REST可以通過在返回的資源中引入鏈接的概念,就可以完成類似GraphQL一樣的批量查詢,包括客戶端智能的根據服務端資源的反饋來確定下一步應該如何動作。即大量文章所指出的GraphQL的客戶端API 可以不隨服務器端的變化而變化的特徵,REST API在演進到了HATEOAS的階段時,也是支持的。

“對於不使用 HATEOAS 的 REST 服務,客戶端和服務器的實現之間是緊密耦合的。客戶端需要根據服務器提供的相關文檔來了解所暴露的資源和對應的操作。當服務器發生了變化時,如修改了資源的 URI,客戶端也需要進行相應的修改。而使用 HATEOAS 的 REST 服務中,客戶端可以通過服務器提供的資源的表達來智能地發現可以執行的操作。當服務器發生了變化時,客戶端並不需要做出修改,因為資源的 URI 和其他信息都是動態發現的。”(來自成富的文章 https://dwz.cn/X6VG4lCS)所以,超媒體這個概念對於REST是如此的重要,也響應了前文講到的“Roy Fielding曾經聲明,如果API不支持超媒體,那麼從技術上講就不是RESTful”這個論斷。

六、GraphQL案例:GitHub

使用GraphQL的一個示例是GitHub GraphQL API。雖然最初的RESTful API很強大,並且完成了所請求的操作,但是GitHub團隊逐漸發現,REST API的靈活性不夠。在談到這個問題時,Github團隊表述是,API的響應“同時發送的數據太多,卻並不包括消費者需要的數據,”這是導致團隊採納GraphQL的最初動因。

白小白:

關於這一點,油管有個講述REST提供冗餘信息的小電影,只有1分鐘,形象生動。還是個程序媛妹子講的,2333。 https://dwz.cn/x0vGzn8F

因此,GitHub需要一種將其內容傳遞給請求者的新的API,這種API不需要進行多次獨立、複雜的調用,可以允許用戶自定義他們的請求,來說明他們到底需要什麼。最重要的是,這種新的API仍然能夠處理大量REST API已經有效處理的基本請求(兼容已有的REST請求)。為此,Github增加了對GraphQL的支持,以提供上述這些關鍵功能。

七、Webhooks概述

GraphQL是擴展API的一種選擇,gRPC是對傳統方法的重新配置,Wehooks是一種完全不同的提供資源的方法,與上述的所有方法都不同。Webhook,簡單來說,就是在事件發生時觸發的HTTP POST請求。

這又是一種對客戶機-服務器模式的逆轉,在傳統方法中,客戶端從服務器請求數據,然後服務器提供給客戶端數據(客戶端是在拉數據)。在Webhook範式下,服務器更新所需提供的資源,然後自動將其作為更新發送到客戶端(服務器是在推數據),客戶端不是請求者,而是被動接收方。

這種控制關係的反轉可以用來促進許多原本需要在遠程服務器上進行更復雜的請求和不斷的輪詢的通信請求。通過簡單地接收資源而不是直接發送請求,我們可以更新遠程代碼庫,輕鬆地分配資源,甚至將其集成到現有系統中來根據API的需要來更新端點和相關數據。

八、Webhook示例:Foursquare,SendGrid

WebHooks是一個相對簡單和有效的設計理念,因此,其實現同樣簡單和有效。Foursquare使用Webhook的方法本質上是建立一個流程,用戶在其中“檢入(checks in)”,就會觸發一個Webhook將更新的內容推送到其他系統和門戶。通過這種方式,用戶可以直接與他們正在訪問的位置交互,同時通過所享用的服務的相似性來建立客人之間的社交關係。

白小白:

Foursquare是一家基於用戶地理位置信息(LBS)的手機服務網站,並鼓勵手機用戶同他人分享自己當前所在地理位置等信息。利用Foursquare服務,手機用戶可“檢入”某個地點,該地點可為全球任何城市的一家飯店、好友家庭居住地或一家商店等等。一旦用戶檢入,Foursquare將把用戶當前所在位置通知給該用戶的其他好友。用戶可以分享關於某地某項產品和服務的體驗。如果某位用戶在特定地點檢入的次數最多,他將獲得該地點虛擬“市長”的頭銜。根據頭銜可以享受商家的免費服務。聽起來有點像大眾點評。

當深入WebHooks的實現細節時,我們通常會看到更復雜的集成場景。例如,SendGrid使用Webhook發送事件數據更新給訂閱客戶,向其告知對許多統計指標的變化。SendGrid甚至實現了一種複合的Webhook方法來解析電子郵件!

白小白:

SendGrid是一個電子郵件服務平臺,可以幫助市場營銷人員跟蹤他們的電子郵件統計數據。如果需要實時獲取發送郵件的狀態(如:發送成功與否,對方有沒有收到,收到之後的處理-打開,刪除,判定為垃圾郵件等),就需要用到SendGrid的WebHook功能來進行實時的數據通知。

九、REST、GraphQL、Webhooks和RPC的場景比較

顯而易見,這些選項中沒有一個比其他選項真正“更好”,而只是某一種更適合於其獨特的交互場景。我們可以將這些場景歸納如下:

REST: 一種著重於進行數據傳輸的依賴超媒體的無狀態體系結構。REST可以將各種各樣的資源綁定在一起,這些資源可能以不同的格式被請求用於不同的目的。REST本質上關心無狀態的資源管理,因此也更適用於這種場景。需要快速迭代和標準化HTTP表達的系統更適合採用REST。

gRPC: 一種用於請求數據的靈活而輕量級的系統。gRPC更適用於系統需要對一定量的數據進行例行處理的情況下,發出數據請求的客戶端要麼是低功耗的,要麼是資源苛刻型的。物聯網就是一個很好的例子。

GraphQL: 一種用戶可以自定義所需數據和格式的方法。GraphQL來自Facebook,其血統很好地展示了它的應用場景,即,請求者需要特定格式的數據來進行特定的使用,在這些場景中,數據格式及其之間的關係至關重要,沒有任何其他解決方案擁有同等程度的數據的組合提供能力。

Webhooks: 數據更新自動完成,而不需要請求。如果API主要用於更新客戶端數據的場景下,最好使用Webhooks。儘管可能這些API還具有其他功能,甚至是RESTful功能,但Webhook的主要用途應該是更新客戶端,在資源新建或者更新時提供更新的、指定的數據。

在這些特定選項中進行選擇,實際上是將您的業務功能與適當的方法相匹配,並確保系統在給定參數範圍內及時響應。

十、結語

選擇一種設計方法也許是API開發的早期最重要的決定。這種設計方法不僅是對API的構建,也影響著最終用戶將如何與API所代表的資源進行交互。換句話說,這不僅僅是開發者層面的實現方法選擇,而是定義了你將如何與你的消費者建立關係。

最終選擇哪種解決方案取決於哪一種更適合你的特定場景。每種解決方案都有其非常具體的目的,因此,說一種解決方案比另一種好是不公平的。更準確的說法是,在執行某種核心功能方面,有些解決方案比其他解決方案更加擅長(類似許多RESTful解決方案試圖模擬RPC功能的嘗試就有待商榷)。

在代碼庫既定的情況下,只有你才能確定哪種解決方案最好。因此,做好功課,並從一開始就選擇正確的方法,以獲得一些真正的收益。你的代碼將更加簡潔,響應性更強,並且適合當前的情況。

附加材料:決策樹

白小白:Phil Sturgeon在apisyouwonthate.com發佈了一張API風格選擇決策樹,正適合作為本文的補充閱讀內容,遺憾的是少了Webhook的部分,好在這部分原本似乎也不是那麼主流????,原文地址是:http://t.cn/E7PVRU3

當然,這一決策樹並沒有考量REST在第4級成熟度的HATEOAS階段的超媒體特性對於一些問題的解決。但還是有一定的參考意義。

基於場景選擇微服務的API範式:REST、GraphQL、Webhooks和gRPC

我將本圖文字化表達如下,並附加了一些個人的理解與本文的結合:

00、開始。

01、客戶端的類型:移動端、網頁、分佈式,轉向2;其他,轉向3;

(這裡的其他,應該就是指一些IOT/低功耗設備的場景,正如前文所述,gRPC更適合的情況)

02、客戶端是否使用共有的流程:是,轉向4;不是,轉向5;

(客戶端使用共有的流程,意味著API可以更容易標準化因而更適合採用REST,而相反,則意味著定製化查詢的需求更普遍,從而更適合合適GraphQL)

03、是否可以立即進行協調一致、原子化的部署:是,轉向12;不是,轉向14;

(RPC依賴服務器和客戶端的自定義協議,一旦API寫就,很難做出變更。即使變更也不是原子化的,因為涉及到服務端與客戶端的代碼定製化做出修改)

04、選擇REST。

05、是否網絡緩存很重要:是,轉向4;不是,轉向6;

06、是否服務端定義的客戶端緩存很重要:是,轉向4;不是,轉向7;

(REST可以在很多層級更容易的實現緩存,包括網關、第三方託管以及客戶端緩存,上述的選擇事實上都是關於是否緩存更加重要。)

07、是否優先考慮減少響應的有效載荷:是,轉向8;不是,轉向4;

08、資源是否還有壓縮的可能:是,轉向4;不是,轉向9;

09、是否需要減少交互次數或者批量獲取:是,轉向10;不是,轉向4;

(上述選擇都是關乎REST的“重”交互方式,正如前文所述,每一次響應是返回全部的數據,這就不利於頻繁交互的場景,除非資源可壓縮,否則更適合GraphQL的場景)

10、類型系統是必須的還是可選的:必須,轉向11;可選,轉向4;

(GraphQL是強數據類型的實現方式)

11、選擇GraphQL。

12、更多遠程系統執行的事件或者操作服務端:遠程命令居多,轉向13;操作服務端,轉向2;

(RPC要求服務端執行大量的計算邏輯)

13、選擇gRPC。

14、是否跨越有邊界的上下文:是,轉向2;不是,轉向13;

(REST請求帶有自描述性,並且資源可以不依賴上下文關係而被理解和識別)

基於場景選擇微服務的API範式:REST、GraphQL、Webhooks和gRPC

關於作者:Kritopher是一位Web開發者和作者,寫作關於安全和商業的文章。自2015年以來,他一直在為Nordic APIs撰寫文章。

關於EAWorld:微服務,DevOps,數據治理,移動架構原創技術分享,長按二維碼關注


分享到:


相關文章: