天天看點

API Gateway 簡介API Gateway 簡介

API Gateway 簡介

本文轉載連結

以下内容摘自《微服務:從設計到部署》

當您選擇将應用程式建構成為一組微服務時,您需要決定應用程式用戶端将如何與微服務進行互動。單體應用程式隻有一組端點(endpoint),通常使用複制(replicated)結合負載均衡來配置設定流量。

然而,在微服務架構中,每個微服務都暴露一組通常比較細顆粒的端點。在本文中,我們将研究如何改進用戶端通信,并提出一個使用 API 網關的方案。

我們假設您正在為一個購物應用開發一個原生移動用戶端。您可能需要實作一個産品詳細資訊頁面,用于展示給定商品的資訊。正如下圖所示,當我們在亞馬遜的安卓移動應用中滾動産品明細頁時,它将會呈現給我們

API Gateway 簡介API Gateway 簡介

這是一個智能手機應用,産品詳細資訊頁面展示了許多資訊。不僅有基本的産品資訊,如名稱、描述和價格,頁面還展示了:

  • 購物車中的物品數量
  • 訂單曆史
  • 客戶評價
  • 低庫存警告
  • 配送選項
  • 各種推薦,包括了購買此産品的客戶購買的其他産品
  • 選擇性購買選項

在使用單體應用架構的情況下,移動用戶端通過對應用程式進行單個 REST 調用來檢索此資料,例如:

GET api.company.com/productdetails/productId
           

負載均衡器将請求路由到幾個相同應用程式執行個體中的其中一個。之後,應用程式查詢各個資料庫表并傳回響應給用戶端。相比之下,當使用微服務架構時,産品詳細頁面上展示的資料來自多個微服務。以下是一些微服務,可能擁有給定産品頁面展示的資料:

  • 訂單服務 — 訂單曆史
  • 目錄(catalog)服務 — 基本的産品資訊,如産品名稱、圖檔和價格
  • 評價服務 — 客戶評價
  • 庫存服務 — 低庫存警告
  • 配送服務 — 配送選項、期限和費用,由配送方的 API 單獨提供
  • 推薦服務 — 推薦類目
API Gateway 簡介API Gateway 簡介

我們需要決定移動用戶端如何通路這些服務。讓我們來看看有哪些方法。

用戶端與微服務直接通信

理論上,用戶端可以直接向每個微服務發送請求。每個微服務都有一個公開的端點:

https://serviceName.api.company.name
           

該 URL 将映射到用于跨可用執行個體分發請求的微服務負載均衡器。為了檢索特定的産品頁面資訊,移動用戶端将向上述的每個微服務發送請求。

不幸的是,這種方式存在着挑戰與限制。第一個問題是用戶端的需求與每個微服務暴露的細粒度的 API 不比對。在此示例中,用戶端需要進行七次單獨請求。如果在更加複雜的應用中,它可能需要做更多的工作。例如,Amazon 展示了在産品頁面渲染中如何牽涉到數百個微服務。雖然用戶端可以通過 LAN 發送許多請求,但在公共網際網路下效率低下,在移動網絡必然是不切實際。

用戶端直接調用微服務存在的另一個問題是有些可能使用了非 web 友好協定。一個服務可能使用了 Thrift 二進制 RPC,而另一個則可能使用 AMQP 消息協定。這兩個協定無論是對浏覽器還是防火牆都是不友好的,最好是在内部使用。應用程式在防火牆之外應該使用 HTTP 或者 WebSocket 之類的協定。

這種方法的另一個缺點是它難以重構微服務。随着時間推移,我們可能會想改變系統劃分服務。例如,我們可能會合并兩個服務或者将服務拆分為兩個或者多個。然而,如果用戶端直接與服務進行通信,實施這類的重構将變得非常困難。

由于存在這些問題,很少有用戶端直接與微服務進行通信。

使用 API 網關

通常更好的方法是使用 API 網關。API 網關是一個伺服器,是系統的單入口點。它類似于面向對象設計模式中的門面(Facade)模式。API 網關封裝了内部系統架構,并針對每個用戶端提供一個定制 API。它還可用于認證、監控、負載均衡、緩存和靜态響應處理。

API Gateway 簡介API Gateway 簡介

API 網關負責請求路由、組合和協定轉換。所有的用戶端請求首先要通過 API 網關,之後請求被路由到适當的服務。API 網關通常會通過調用多個微服務和聚合結果來處理一個請求。它可以在 Web 協定(如 HTTP 和 WebSocket)和用于内部的非 Web 友好協定之間進行轉換。

API 還可以為每個用戶端提供一個定制 API。它通常會為移動用戶端暴露一個粗粒度的 API。例如,考慮一下産品詳細資訊場景。API 網關可以提供一個端點 /productdetails?productid=xxx,如上圖所示,一個使用了 API 網關的微服務。允許移動用戶端通過一個單獨的請求來檢索所有産品詳細資訊。API 網關通過調用各種服務(産品資訊、推薦、評價等)并組合結果。

一個很好的 API 網關案例是 Netflix API 網關。Netflix 流媒體服務可用于數百種不同類型的裝置,包括電視機、機頂盒、智能手機、遊戲機和平闆電腦等。起初,Netflix 嘗試為他們的流媒體服務提供一個通用的 API。後來,他們發現由于裝置種類繁多,并且他們各自有着不同需求,是以并不是能很好地運作。如今,他們使用了 API 網關,通過運作特定裝置适配代碼來為每個裝置提供一個定制 API。

API 網關的優點與缺點

正如您所料,使用 API 網關同樣存在好處與壞處。使用 API 網關的主要好處是它封裝了應用程式的内部結構。用戶端隻需要與網關通信,而不必調用特定的服務。API 網關為每種類型的用戶端提供了特定的 API,減少了用戶端與應用程式之間的往返次數。同時,它還簡化了用戶端的代碼。

API 網關也存在一些缺點,它是另一個高度可用的元件,需要開發、部署和管理。另外,還有一個風險是 API 網關可能會成為開發瓶頸。開發人員必須更新 API 網關以暴露每個微服務的端點。

重要的是更新 API 網關的過程應盡可能地放緩一些。否則,開發人員将被迫排隊等待網關更新。盡管 API 網關存在這些缺點,但對于大多數的真實應用來說,使用 API 是合理的。

實施 API 網關

我們已經了解了使用 API 網關的動機與權衡。接下來讓我們看看您需要考慮的各種設計問題。

性能與可擴充性

隻有少數公司能達到 Netflix 的營運規模,每天需要處理數十億的請求。然而,對于大多數應用來說,API 網關的性能和可擴充性是相當重要的。是以,在一個支援異步、非阻塞 I/O 平台上建構 API 網關是很有必要的。可以使用不同的技術來實作一個可擴充的 API 網關。在 JVM 上,您可以使用基于 NIO 的架構,如 Netty、Vertx、Spring Reactor 或者 JBoss Undertow。一個流行的非 JVM 選擇是使用 Node.js,它是一個建立在 Chrome 的 JavaScript 引擎之上的平台。

使用響應式程式設計模型

API 網關通過簡單地把他們(請求)路由到适當的後端服務來處理一些請求。它通過調用多個後端服務并聚合結果來處理其他請求。對于某些請求,如産品詳細資訊請求,對後端服務請求而言是彼此獨立的。為了把響應時間縮短到最小,API 網關應該并發執行獨立請求。

然而,有時候,請求是互相依賴的。首先,API 網關可能需要在将請求路由到後端服務之前,通過調用驗證服務來驗證請求。同樣,為了從客戶的願望清單中擷取産品資訊,API 網關首先必須檢索包含該資訊的客戶資料,然後檢索每個産品的資訊。另一個有趣的 API 組合案例是 Netflix 視訊網格。

使用傳統的異步回調方式來編寫 API 組合代碼會很快使你陷入回調地獄。代碼将會變得雜亂、難以了解并且容易出錯。一個更好的方式是使用響應式方法以聲明式編寫 API 網關代碼。響應式抽象的例子包括 Scala 的 Future、Java 8 中的 CompletableFuture 和 JavaScript 中的 Promise。還有 Reactive Extensions(也稱為 Rx 或 ReactiveX),最初由 Microsoft 為 .NET 平台開發。Netflix 為 JVM 建立了 RxJava,專門應用于其 API 網關。還有用于 JavaScript 的 RxJS,它可以在浏覽器和 Node.js 中運作。使用響應式方式可讓您能夠編寫出簡單而高效的 API 網關代碼。

服務調用

一個基于微服務的應用程式是一個分布式系統,必須使用一個程序間(inter-process)通信機制。有兩種程序間通信方案。一是使用基于消息的異步機制。某些實作采用了消息代理,如 JMS 和 AMQP。其他采用無代理的方式直接與服務通信,如 Zeromq。

另一種類型的程序間通信采用了同步機制,如 HTTP 和 Thrift。系統通常會同時使用異步和同步方式。甚至可以為每種方式應用多個實作。是以,API 網關需要支援各種通信機制。

服務發現

API 網關需要知道與其通信的每個微服務的位置(IP 位址和端口)。在傳統應用程式中,您可以将這些位置寫死,但在現代基于雲的微服務應用程式中,找到所需的位置不是一件簡單的事情。

基礎設施服務(比如消息代理)通常都有一個可以通過系統環境變量來指定的靜态位置。但是,要确定應用程式服務的位置并不是那麼容易。

應用服務可以動态配置設定位置。此外,由于自動擴縮和更新,一個服務的整組執行個體可以動态變更。是以,API 網關與系統中的任何其他服務用戶端一樣,需要使用系統的服務發現機制:服務端發現或用戶端發現。第四章中更詳細地描述了服務發現。現在需要注意的是,如果系統使用用戶端發現,API 網關必須能夠查詢服務注冊中心,該注冊中心是所有微服務執行個體及其位置的資料庫。

處理局部故障

實施 API 網關時必須解決的另一個問題是局部故障問題。當一個服務調用另一個響應緩慢或者不可用的服務時,所有分布式系統都會出現此問題。API 網關不應該無期限地等待下遊服務。但是,如何處理故障問題取決于特定的方案和哪些服務發生故障。例如,如果推薦服務在擷取産品詳細資訊時沒有響應,API 網關應将其餘的産品詳細資訊傳回給用戶端,因為它們對使用者仍然有用。建議可以是空的,也可以用其他代替,例如寫死的十強名單。然而,如果産品資訊服務沒有響應,那麼 API 網關應該向用戶端傳回錯誤。

如果可以,API 網關還可以傳回緩存資料。例如,由于産品價格變化不大,當價格服務不可用時,API 網關可以傳回被緩存的價格資料。資料可以由 API 網關緩存或存儲在外部緩存中,如 Redis 或 Memcached。API 網關通過傳回預設資料或緩存資料,確定系統發生故障時最小程度上影響到使用者體驗。

Netflix Hystrix 是一個非常有用的庫,用于編寫調用遠端服務代碼。Hystrix 可以使超出指定門檻值的調用逾時。它實作了斷路器模式,防止用戶端不必要地等待無響應的服務。如果服務的錯誤率超過指定門檻值,Hystrix 将會跳閘,所有請求将在指定的時間内立即失敗。Hystrix 允許您在請求失敗時定義回退操作,例如從緩存讀取或傳回預設值。如果您正在使用 JVM,那麼您一定要考慮使用 Hystrix。如果您是在非 JVM 環境中運作,則應使用同等作用的庫。

總結

對于大多數基于微服務的應用程式來說,實作一個 API 網關是很有意義的,API 網關充當着系統的單入口點,并且負責請求路由,組合和協定轉換。它為每個應用程式用戶端提供了一個自定義 API。API 網關還可以通過傳回緩存或預設資料來掩蓋後端服務故障。

繼續閱讀