1. 程式人生 > 其它 >剛哥談架構(八)- 為你的應用選擇合適的API

剛哥談架構(八)- 為你的應用選擇合適的API

前言:

架構師的主要活動是做出正確的技術決策。選擇合適的API是一項重要的技術決策。那麼今天就看看API的選擇問題。

應用程式程式設計介面(API)是一種計算介面,它定義了多個軟體中介之間的互動。它定義了可以進行的呼叫或請求的型別,如何進行呼叫,應使用的資料格式,遵循的約定等。它還可以提供擴充套件機制,以便使用者可以以各種方式擴充套件現有功能。在不同程度上。API可以是完全定製的,特定於元件,也可以基於行業標準進行設計以確保互操作性。有些API必須記錄在案,而其它API則經過設計,以便可以“查詢”它們以確定支援的功能。由於其他元件/系統僅依賴於API,因此提供API的系統可以(理想地)在API的“後面”更改其內部詳細資訊,而不會影響其使用者。

正如上述的定義所述,API提供了多個軟體之間的互動。所以我們這裡強調的是互動性。我們在使用任何的語言開發一個應用的時候,都會提供內部的基於該語言的API,這種內部的API不是我們今天要討論的內容,因為這種內部的互動不涉及到軟體之間。我們今天要討論的API主要要涉及到系統之間的互動。對於具體應用而言,更多是程序之間(本機),主機之間(本網路),服務之間(可能跨域廣域網)的互動。

目錄:

1、CORBA

2、XML-RPC / SOAP

3、REST

4、GraphQL

5、gRPC

最早在Unix/Linux的程式設計領域,提供了程序間通訊的手段,例如:管道,訊號量,訊息佇列,套接字(Socket)等。如果你的應用是由不同語言編寫的,那麼這裡只能選擇Socket通訊作為應用之間的API手段。但是Socket通訊是一種非常低Level的通訊手段,它以底層的資料包作為抽象和通訊內容,很難維護和使用。當然還有一些其它的系統間通訊的手段例如通過共享檔案或者FTP的方式,同樣面臨著各種不便。我們希望提供一種更高階的互動手段,直接和我的應用的抽象互動,這些抽象可能是方法,函式和物件。於是就有了各種支撐這些需求的API技術。

早期的程序間通訊技術包括:

  • DCOM( Distributed Component Object Model )分散式元件物件模型,這個是微軟的技術,只能用於Windows平臺, 通過網路實現遠端物件間的通訊
  • RMI( Remote Method Call) Java的遠端方法呼叫,這個是Java自己的RPC,只能用於Java應用之間的遠端呼叫。
  • JNIJava的本地介面, 支援Java應用呼叫本地方法,這個是跨越語言障礙的,但是僅僅侷限於Java應用呼叫其它的本地應用,不具備互操作性,是個單向通道。

1.CORBA

在1991年一種名叫CORBA ( Common Object Request Broker Architecture )的技術出現了,我記得我的第一份工作是一個電信網管系統的開發,我們就是利用CORBA來實現不同的系統之間的通訊。主要涉及C++和Java。

CORBA和之前提到的DCOM和RMI類似,都提供了遠端的物件/方法呼叫,但是CORBA是一種與語言和實現無關的技術,我記得我們當時的測試指令碼使用了TCL,也有CORBA的實現,也就是說CORBA定了與語言解耦的系統間通訊的標準。這個是它的最大的優勢。那個年代的應用,採用CORBA作為系統間的通訊手段非常普遍。

開發CORAB的過程從IDL的定義開始,使用者通過IDL定義了物件,然後在Server端實現該物件的應用邏輯,在Client端呼叫該物件。

但是CORBA並非沒有缺點,否則我們也不會很少再看見今天的應用用CORAB作為API的了。他的主要問題是:

  • 物件的生命週期管理比較複雜。遠端物件的發現,建立和銷燬都會帶來問題
  • 整個CORAB的架構比較複雜,看看它的架構圖就知道了

總之,今天你要開發一個引用,除非要個已有系統互動,你應該不會選擇CORBA。

2.XML-RPC / SOAP

XML-RPC發表於1998年,由UserLand Software(UserLand Software)的Dave Winer及Microsoft共同發表。後來在新的功能不斷被引入下,這個標準慢慢演變成為今日的SOAP協議

下面是一個 XML-RPC的請求/響應的例子:

<?xml version="1.0"?><methodCall> <methodName>examples.getStateName</methodName> <params>   
<param>       
  <value><i4>40</i4></value>   
  </param> </params></methodCall><?xml version="1.0"?><methodResponse> <params>   
  <param>       
  <value><string>South Dakota</string></value>   
  </param> </params></methodResponse>

SOAP是Simple Object Access Protocol的縮寫。SOAP為Web服務提供了Web服務協議棧的Messaging Protocol層。它是一個基於XML的協議,由三部分組成:

  1. 一個信封,它定義了訊息結構以及如何處理它
  2. 一組用於表達應用程式定義的資料型別例項的編碼規則
  3. 表示過程呼叫和響應的約定

SOAP具有三個主要特徵:

  1. 可擴充套件性(安全性和WS-Addressing在開發中)
  2. 中立性(SOAP可以通過HTTP,SMTP,TCP,UDP等任何協議進行操作)
  3. 獨立性(SOAP允許任何程式語言)

作為SOAP過程可以執行的操作的示例,應用程式可以將SOAP請求傳送到啟用了帶有搜尋引數的Web服務的伺服器(例如,房地產價格資料庫)。然後,伺服器返回SOAP響應(包含結果資料的XML格式的文件),例如價格,位置,功能。由於生成的資料採用標準化的機器可解析格式,因此發出請求的應用程式可以直接將其整合。

SOAP體系結構由以下幾層規範組成:

  • 訊息格式
  • 郵件交換模式(MEP)
  • 底層傳輸協議繫結
  • 訊息處理模型
  • 協議可擴充套件性

這裡是一個SOAP訊息的例子:

POST /InStock HTTP/1.1Host: www.example.orgContent-Type: application/soap+xml; 
charset=utf-8Content-Length: 299SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
<?xml version="1.0"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"xmlns:m="http://www.example.org"> <soap:Header> </soap:Header> <soap:Body>   
<m:GetStockPrice>     
  <m:StockName>T</m:StockName>   
</m:GetStockPrice> </soap:Body></soap:Envelope>

相比較XML-RPC,它的功能更多,當然訊息結構也更復雜。

SOAP是W3C推薦的Webservice標準,一度也是非常的流行,但是我們看到基於XML的訊息比較複雜,訊息本身因為XML的原因,有相當多的開銷。於是後面又有了基於JSON的RPC格式。但總的來說,SOAP也已經是昨日黃花,當今的應用構建,你選它的概率應該也不大了。

3.REST

REST是當今最為流行的API。因為大量的Web應用採用REST作為其API的選擇。REST是Representational State Transfer的縮寫。是Roy Thomas Fielding博士於2000年在他的博士論文中提出來的一種全球資訊網軟體架構風格。

目的是便於不同軟體/程式在網路(例如網際網路)中互相傳遞資訊。表現層狀態轉換是根基於超文字傳輸協議(HTTP)之上而確定的一組約束和屬性,是一種設計提供全球資訊網絡服務的軟體構建風格。符合或兼容於這種架構風格(簡稱為 REST 或 RESTful)的網路服務,允許客戶端發出以統一資源識別符號訪問和操作網路資源的請求,而與預先定義好的無狀態操作集一致化。因此表現層狀態轉換提供了在網際網路絡的計算系統之間,彼此資源可互動使用的協作性質(interoperability)。

相對於其它種類的網路服務,例如SOAP服務,則是以本身所定義的操作集,來訪問網路上的資源。目前在三種主流的Web服務實現方案中,因為REST模式與複雜的SOAP和XML-RPC相比更加簡潔,越來越多的Web服務開始採用REST風格設計和實現。所以我們可以看到軟體的發展,大體是從複雜變得簡單,只有簡單的東西才會變得更有生命力。

為了使任何應用程式真正實現RESTful,必須遵循六個體系結構約束:

  • 統一介面:意味著必須向Web應用程式中的API使用者提供API介面。
  • 客戶端伺服器:客戶端和伺服器必須彼此獨立,並且客戶端應僅知道資源的URI。
  • 無狀態:伺服器不得儲存與客戶端請求相關的任何內容。客戶端負責維護應用程式的狀態。
  • 可快取的:資源必須可快取。
  • 分層系統:體系結構必須是分層的,這意味著體系結構的元件可以位於多個伺服器中。
  • 按需程式碼:客戶端必須能夠獲取可執行程式碼作為響應。這是一個可選約束。

基於REST的Web服務被稱為RESTful Web服務。在這些應用程式中,每個元件都是一種資源,可以使用HTTP標準方法通過公共介面訪問這些資源。以下四種HTTP方法通常用於基於REST的體系結構中:

  • GET-對資源的只讀訪問。
  • POST —建立一個新資源。
  • DELETE—刪除資源。
  • PUT-更新現有資源/建立新資源。

RESTFul風格API所有的操作都是一個動詞,對應HTTP請求的一種型別。每一個操作都定義了對操作的資源的某種行為。這種抽象,特別適合相當多的Web應用,後臺是一個數據庫,每一個REST的端點對應了一張資料庫的表,很自然的利用REST操作來實現表的增刪查改。

當然RESTFul的風格也有它的不足:

  • 不是所有的應用操作都可以用資源的增刪查改來對應,在實際的開發中經常會需要把一個操作對映為一個資源這種不倫不類的行為。
  • REST是同步服務,如果需要可能要引入回撥機制。例如Webhook。
  • REST只提供客戶端呼叫伺服器的選項,不支援伺服器端發起請求。

於是新的API型別會出現來解決這些問題。

4.GraphQL

GraphQL是一個開源的API資料查詢和操作語言及實現為了實現上述操作的相應執行環境。2012年,GraphQL由Facebook內部開發,2015年公開公佈。2018年11月7日,Facebook將GraphQL專案轉移到新成立的GraphQL基金會 。

GraphQL規範概述了5條設計原則,這使其成為現代前端開發的精心設計的解決方案。讓我們研究一下GraphQL的設計原則。

  • 查詢是分層結構的,具有分層和巢狀欄位,查詢與響應資料一對一匹配。查詢和響應的形狀像樹,可以查詢每個專案的其他巢狀欄位。
  • 該結構以產品為中心,著重於前端希望如何接收資料,並構建交付所需的執行時。這樣一來,就可以向後端請求一個所需的所有資料,然後讓伺服器根據GraphQL的規範從不同的端點獲取資料。
  • 它使用特定於應用程式的型別系統,使開發人員能夠確保查詢使用有效型別,並且在執行之前在語法上正確。
  • GraphQL查詢是在客戶端指定的,因此客戶端確切知道它將以什麼格式接收資料。
  • 帶有GraphQL的伺服器結構必須是自包含的,或者可由GraphQL本身查詢。這將啟用功能強大的開發人員工具,例如GraphiQL或GraphQL Playground,這兩種工具都將使開發人員能夠準確檢視哪些查詢和欄位可供他們在伺服器中使用。

像RESTful API一樣,GraphQL API旨在處理HTTP請求並提供對這些請求的響應。但是,相似之處到此結束。在REST API建立在請求方法和端點之間的連線上的情況下,GraphQL API設計為僅使用一個始終通過POST請求查詢的端點,通常使用URL http://yourdomain.com/graphql。

達到GraphQL端點後,客戶端請求的負擔將完全在請求主體內處理。該請求主體必須遵守GraphQL規範,並且API必須具有適當的伺服器端邏輯來處理這些請求並提供適當的響應。與RESTful API相比,這提供了更流暢的客戶端體驗,後者可能要求客戶端對多個數據進行多次請求,並在資料返回後進行操作。

如上圖的例子,使用者通過RESTFul的API來請求資料,需要兩個GET請求,先獲取Assets,再通過AssetID獲取comments。而通過GraphQL,使用者只需要描述需要請求的資料的結構和條件,就可以通過一個請求獲取全部所需要的資料,簡化了客戶端與伺服器的互動。

GraphQL提供的效能優於REST API,可以為前端開發人員帶來回報。使用GraphQL規範建立伺服器可能需要更多設定和編寫預測性伺服器端邏輯來解析和處理請求。儘管GraphQL的安裝成本可能會高於傳統的REST架構,但更具可維護性的程式碼,強大的開發工具以及簡化的客戶端查詢,這些都是不錯的收益。

除了靈活性這個最大的優點外,GraphQL還有以下的優點:

  • 宣告性的資料獲取,避免了客戶端和伺服器端的額外互動
  • 優秀的開發體驗,不需要版本控制,因為引入新的欄位不會影響到API查詢。同時客戶端和伺服器端的團隊可以並行的獨立工作。
  • 強型別的GraphQL模式使得程式碼可預測,並及早發現錯誤。

當然,GraphQL也不是沒有缺點:

  • 使用GraphQL,如果您需要查詢有關列表或記錄集合的資訊,則處理起來會很棘手。例如,如果您想獲取包含其地址的使用者列表的詳細資訊,則它將執行n + 1個查詢。一個用於使用者列表,然後n查詢每個使用者的地址。現在它會嚴重影響效能,因此必須非常小心地處理它。
  • 很難快取,快取API響應的目的主要是為了更快地從將來的請求中獲取響應。與GraphQL不同,RESTful API可以利用HTTP規範中內建的快取。正如前面提到的,GraphQL查詢可以請求資源的任何欄位,因此快取本質上是困難的。

5.gRPC

gRPC是一個開源的遠端過程呼叫框架,用於在服務之間進行高效能的通訊。這是將以不同語言編寫的服務與可插拔支援(用於負載平衡,跟蹤,執行狀況檢查和身份驗證)相連線的有效方法。預設情況下,gRPC使用Protobuf(協議緩衝區)序列化結構化資料。通常,對於微服務體系結構,gRPC被認為是REST協議的更好替代方案。gRPC中的" g"可以歸因於最初開發該技術的Google。

gRPC是對傳統RPC框架的改編。那麼,它與現有的RPC框架有何不同?

最重要的區別是gRPC使用protobuf 協議緩衝區作為介面定義語言進行序列化和通訊,而不是JSON / XML。協議緩衝區可以描述資料的結構,並且可以從該描述中生成程式碼,以生成或解析表示結構化資料的位元組流。這就是為什麼gRPC首選多語言(使用不同技術實現)的Web應用程式的原因。二進位制資料格式使通訊更輕鬆。gRPC也可以與其他資料格式一起使用,但是首選的是protobuf。

同樣,gRPC建立在HTTP / 2之上,它支援雙向通訊以及傳統的請求/響應。gRPC允許伺服器和客戶端之間的鬆散耦合。在實踐中,客戶端開啟與gRPC伺服器的長期連線,並且將為每個RPC呼叫開啟一個新的HTTP / 2流。

如上圖所示,gRPC支援不同模式的客戶端和伺服器端的通訊方式,極大的方便了不同的互操作能力。

與使用JSON(主要是JSON)的REST不同,gRPC使用Protobuf,這是編碼資料的更好方法。由於JSON是基於文字的格式,因此它比protobuf格式的壓縮資料要重得多。與REST相比,gRPC的另一個顯著改進是它使用HTTP 2作為其傳輸協議。REST使用的HTTP 1.1基本上是一個請求-響應模型。gRPC利用HTTP 2的雙向通訊功能以及傳統的響應請求結構。在HTTP 1.1中,當多個請求來自多個客戶端時,它們將被一一處理。這會降低系統速度。HTTP 2允許多路複用,因此可以同時處理多個請求和響應。

gRPC的開發模式和之前提到的CORBA有些類似。Protobuf充當了IDL的角色,然後利用工具生成各種語言的程式碼,最後在生成的程式碼上實現伺服器端和客戶端的邏輯。

gRPC的優點是:

  • 出色的效能,因為採用protobuf編碼和http/2
  • 支援伺服器端和客戶端的雙向通訊
  • 易用,相比REST開發,需要更少的程式碼

缺點:

  • 更陡峭的學習曲線
  • 支援的語言的種類沒有REST多,當然它還在發展中
  • 因為需要Protobuf的編譯,這帶來了伺服器和客戶端一定的耦合,因為介面變動的時候需要重新編譯生成程式碼。對於REST,基於不同的工具鏈可能有不同的解決方案

因為其高效能,gRPC更適合被用於系統內部元件的通訊選擇。在下圖的微服務架構中,對外的服務採用了REST或者GraphQL的API,而內部微服務之間使用的是gRPC。

6.總結

好了,看了這麼多的API選擇之後,我們做一個小結。

系統間的API選項經過多年的發展,現階段的主流是RESTful API,gRPC 和GraphQL。具體怎麼選擇,要結合你的業務上下文,我的推薦是:

  1. 對外提供的公開服務,首選RESTFul API,因為它非常成熟穩定和流行,語言和工具鏈的支援都很好。
  2. 如果你希望加速應用的客戶端開發,GraphQL是個不錯的選擇,提供良好的效能和靈活性
  3. 如果你的應用特別看重效能,而且主要是內部系統之間的互動,建議考慮gRPC