關於API gateway

當選擇將應用程序構建爲一組微服務時,需要確定應用程序的客戶端如何與微服務進行交互。 對於單體應用程序而言,只有一組(通常是負載平衡的)endpoint。 但是,在微服務架構中,每個微服務都公開了一組通常是細粒度的endpoint。 這會如何影響客戶端到應用程序的通信呢。

假設我們正在爲購物應用程序開發本機移動客戶端。 我們可能需要實現一個產品詳細信息頁面,該頁面顯示有關給定產品的信息。例如,下圖顯示了在應用程序中滾動產品詳細信息時將看到的內容。

Indexed elements of Amazon's mobile app for Android, as they appear on a mobile phone screen

即使這是智能手機應用程序,“產品詳細信息”頁面也會顯示很多信息。例如,不僅有基本的產品信息(例如名稱,描述和價格),而且此頁面還顯示:

  1. 購物車中的物品數量
  2. 訂單歷史
  3. 顧客評論
  4. 庫存不足警告
  5. 送貨選項
  6. 各種建議,包括該產品經常購買的其他產品,購買此產品的客戶購買的其他產品以及購買此產品的客戶查看的其他產品
  7. 替代購買選項

使用整體應用程序體系結構時,移動客戶端將通過對應用程序進行單個REST調用(GET api.company.com/productdetails/productId)來檢索此數據。負載平衡器將請求路由到N個相同的應用程序實例之一。然後,應用程序將查詢各種數據庫表,並將響應返回給客戶端。

相反,在使用微服務架構時,產品詳細信息頁面上顯示的數據由多個微服務擁有。以下是一些可能的微服務,這些微服務擁有在示例產品詳細信息頁面上顯示的數據:

  1. 購物車服務–購物車中的物品數量
  2. 訂單服務–訂單歷史記錄
  3. 目錄服務–基本產品信息,例如其名稱,圖像和價格
  4. 審覈服務–客戶評論
  5. 庫存服務–庫存不足警告
  6. 運送服務–運送選項,期限和費用與運送提供商的API分開提取
  7. 推薦服務–建議項目

如下圖所示:

Mobile client of ecommerce app needs a way to access the RESTful APIs of the 7 microservices

我們需要確定移動客戶端如何訪問這些服務。 怎麼做呢?我們可以用下面這些選項:

客戶端到微服務的直接通信

從理論上講,客戶端可以直接向每個微服務發出請求。每個微服務都有一個public endpoint(https://serviceName.api.company.name)。該URL將映射到微服務的負載平衡器,該負載平衡器在可用實例之間分配請求。要檢索產品詳細信息,移動客戶端將向上面列出的每個服務發出請求。

不幸的是,此選項存在挑戰和侷限性。一個問題是客戶端需求與每個微服務公開的細粒度API之間的不匹配。在此示例中,客戶端必須發出七個單獨的請求。在更復雜的應用程序中,可能需要做更多的工作。例如,亞馬遜描述瞭如何在呈現其產品頁面時涉及數百種服務。儘管客戶端可以通過LAN發出許多請求,但在公共Internet上可能效率太低,並且在移動網絡上肯定是不切實際的。這種方法還使客戶端代碼更加複雜。

客戶端直接調用微服務的另一個問題是,有些服務可能使用不支持Web的協議。一個服務可能使用Thrift二進制RPC,而另一服務可能使用AMQP消息傳遞協議。兩種協議都不是特別適合瀏覽器或防火牆的協議,並且最好在內部使用。應用程序應在防火牆外部使用HTTP和WebSocket之類的協議。

這種方法的另一個缺點是很難重構微服務。隨着時間的流逝,我們可能想更改將系統劃分爲服務的方式。例如,我們可以合併兩個服務或將一個服務拆分爲兩個或多個服務。但是,如果客戶直接與服務進行通信,那麼執行這種重構可能會非常困難。

由於這些問題,客戶端很少直接與微服務進行通信。

使用API Gateway

通常,更好的方法是使用所謂的API gateway即api網關。 API網關是服務器,是系統的單個入口點。 它與面向對象設計中的Facade模式相似。 API網關封裝了內部系統架構,並提供了針對每個客戶端量身定製的API。 它可能還具有其他職責,例如身份驗證,監視,負載平衡,緩存,請求重構和管理以及靜態響應處理。

下圖顯示了API網關通常如何適應體系結構

An API gateway enables mobile clients of ecommerce app to access the RESTful APIs of its 7 microservices

API網關負責請求路由,組合和協議轉換。來自客戶端的所有請求都首先經過API網關。然後,它將請求路由到適當的微服務。 API網關通常會通過調用多個微服務並彙總結果來處理請求。它可以在內部使用的HTTP和WebSocket之類的Web協議與Web不友好的協議之間轉換。

API網關還可以爲每個客戶端提供自定義API。它通常爲移動客戶端提供粗粒度的API。例如,考慮產品詳細信息場景。 API網關可以提供一個端點(/ productdetails?productid = xxx),該端點使移動客戶端可以通過單個請求檢索所有產品詳細信息。 API網關通過調用各種服務(產品信息,建議,評論等)並組合結果來處理請求。

Netflix API Gateway是API網關的一個很好的例子。 Netflix流媒體服務可在數百種不同的設備上使用,包括電視,機頂盒,智能手機,遊戲系統,平板電腦等。最初,Netflix嘗試爲其流媒體服務提供一種通用的API。但是,他們發現,由於設備種類繁多以及其獨特的需求,它不能很好地工作。後來,他們使用API​​網關,該網關通過運行特定於設備的適配器代碼爲每個設備提供量身定製的API。適配器通常通過平均調用六到七個後端服務來處理每個請求。 Netflix API網關每天處理數十億個請求。

API Gateway的優缺點

凡事無絕對,使用API​​網關既有優點也有缺點。使用API​​網關的主要好處是它封裝了應用程序的內部結構。客戶端不必調用特定的服務,而只是與網關進行對話。 API網關爲每種客戶端提供特定的API。這減少了客戶端與應用程序之間的往返次數。它還簡化了客戶端代碼。

API網關也有一些缺點。因爲它本身是一個必須進行開發,部署和管理的高可用性組件。 API網關也有成爲開發瓶頸的風險。開發人員必須更新API網關才能公開每個微服務的端點。重要的是,更新API網關的過程應儘可能輕巧。否則,開發人員將被迫排隊等待更新網關。儘管有這些缺點,但是對於大多數實際應用程序而言,使用API​​網關還是有意義的。

實現一個API Gateway

現在,我們已經瞭解了使用API​​網關的動機和取捨,現在讓我們看看實現api gateway需要考慮的各種設計問題。

性能和可伸縮性
只有少數幾家公司擁有Netflix的規模,每天需要處理數十億個請求。但是,對於大多數應用程序而言,API網關的性能和可伸縮性通常非常重要。因此,支持異步請求,非阻塞I / O的API網關是有意義的。有多種不同的技術可用於實現可伸縮的API網關。在JVM上,您可以使用基於NIO的框架之一,例如Netty,Vertx,Spring Reactor或JBoss Undertow。一種流行的非JVM選項是Node.js,它是基於Chrome的JavaScript引擎構建的平臺。另一種選擇是使用NGINX Plus。 NGINX Plus提供了易於部署,配置和編程的成熟,可擴展的高性能Web服務器和反向代理。 NGINX Plus可以管理身份驗證,訪問控制,負載平衡請求,緩存響應,並提供可感知應用程序的運行狀況檢查和監視。

使用反應式編程模型
API網關通過簡單地將請求路由到適當的後端服務來處理一些請求。它通過調用多個後端服務並彙總結果來處理其他請求。對於某些請求(例如產品詳細信息請求),對後端服務的請求彼此獨立。爲了最小化響應時間,API網關應同時執行獨立的請求。但是,有時請求之間存在依賴關係。在將請求路由到後端服務之前,API網關可能首先需要通過調用身份驗證服務來驗證請求。同樣,要在客戶的願望清單中獲取有關產品的信息,API網關必須首先檢索包含該信息的客戶資料,然後爲每個產品檢索信息。 API組成的另一個有趣示例是Netflix Video Grid。

使用傳統的異步回調方法編寫API組合代碼會很快導致您陷入困境。該代碼將混亂,難以理解且容易出錯。更好的方法是使用反應式方法以聲明式編寫API網關代碼。反應式抽象的示例包括Scala中的Future,Java 8中的CompletableFuture和JavaScript中的Promise。還有Reactive Extensions(也稱爲Rx或ReactiveX),它最初是由Microsoft爲.NET平臺開發的。 Netflix爲JVM創建了RxJava,專門用於其API網關。還有用於JavaScript的RxJS,它可以在瀏覽器和Node.js中運行。使用反應式方法將使您能夠編寫簡單而有效的API網關代碼。

服務調用
基於微服務的應用程序是一個分佈式系統,必須使用進程間通信機制。進程間通信有兩種樣式。一種選擇是使用基於消息的異步機制。一些實現使用消息代理,例如JMS或AMQP。諸如Zeromq之類的其他公司則是沒有broker的,服務之間直接通信。進程間通信的另一種形式是同步機制,例如HTTP或Thrift。系統通常會同時使用異步和同步樣式。它甚至可以使用每種樣式的多個實現。因此,API網關將需要支持多種通信機制。

服務發現
API網關需要知道與之通信的每個微服務的位置(IP地址和端口)。在傳統的應用程序中,您可能需要對位置進行硬連線,但是在現代的基於雲的微服務應用程序中,這是一個不小的問題。基礎結構服務(例如消息代理)通常將具有靜態位置,可以通過OS環境變量指定該位置。但是,確定應用程序服務的位置並非易事。應用程序服務具有動態分配的位置。而且,服務的實例集會由於autoscaling 和upgrades而動態更改。因此,API網關與系統中的其他任何服務客戶端一樣,需要使用系統的服務發現機制:服務器端發現或客戶端端發現。如果系統使用客戶端發現,則API網關必須能夠查詢服務註冊表,該註冊表是所有微服務實例及其位置的數據庫。這一部分的具體實現這裏不做展開,可以參考博客:使用zookeeper實現服務註冊與發現

處理部分故障

實現API網關時必須解決的另一個問題是部分失敗的問題。每當一個服務調用另一個響應緩慢或不可用的服務時,在所有分佈式系統中都會出現此問題。 API網關絕不應無限期地阻塞等待下游服務。但是,它如何處理故障取決於特定的情況以及哪個服務出現故障。例如,如果推薦服務在產品詳細信息場景中無響應,則API網關應將其餘產品詳細信息返回給客戶端,因爲它們仍然對用戶有用。這些建議可以是空的,也可以由例如前十名的硬列表取代。但是,如果產品信息服務無響應,則API Gateway應該將錯誤返回給客戶端。

如果可用,API網關也可以返回緩存的數據。例如,由於產品價格很少變化,因此如果定價服務不可用,API網關可以返回緩存的定價數據。數據可以由API網關本身緩存,也可以存儲在外部緩存中,例如Redis或Memcached。通過返回默認數據或緩存的數據,API網關可確保系統故障不會影響用戶體驗。

Netflix Hystrix是一個非常有用的庫,用於編寫調用遠程服務的代碼。 Hystrix使超出指定閾值的呼叫超時。它實現了斷路器模式,可阻止客戶端不必要地等待無響應的服務。如果服務的錯誤率超過指定的閾值,則Hystrix將使斷路器跳閘,並且所有請求將在指定的時間內立即失敗。 Hystrix允許您定義請求失敗時的回退操作,例如從緩存中讀取或返回默認值。如果您使用的是JVM,則絕對應該考慮使用Hystrix。並且,如果您在非JVM環境中運行,則應使用等效的庫。

總結

對於大多數基於微服務的應用程序而言,實現一個API網關是有意義的,該網關充當系統的單個入口點。 API網關負責請求路由,組合和協議轉換。 它爲應用程序的每個客戶端提供了自定義API。 API網關還可以通過返回緩存或默認數據來掩蓋後端服務中的故障。 

p.s 本篇博客參考nginx官方網站

 

 

 

 

 

 

 

 

 

 

 

 

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