構建微服務:使用 API 網關

fans news 發佈 2022-01-27T04:37:48+00:00

當您選擇將應用程式構建為一組微服務時,您需要決定應用程式的客戶端將如何與微服務交互。對於單體應用程式,只有一組(通常是複製的、負載平衡的)端點。然而,在微服務架構中,每個微服務都暴露了一組通常是細粒度的端點。

當您選擇將應用程式構建為一組微服務時,您需要決定應用程式的客戶端將如何與微服務交互。對於單體應用程式,只有一組(通常是複製的、負載平衡的)端點。然而,在微服務架構中,每個微服務都暴露了一組通常是細粒度的端點。在本文中,我們研究了這如何影響客戶端到應用程式的通信,並提出了一種使用API 網關的方法。

介紹

假設您正在為購物應用程式開發本機移動客戶端。您可能需要實現一個產品詳細信息頁面,該頁面顯示任何給定產品的信息。

例如,下圖顯示了您在亞馬遜的Android 移動應用程式中滾動瀏覽產品詳細信息時看到的內容。

打開百度APP看高清圖片

即使這是一個智慧型手機應用程式,產品詳細信息頁面也會顯示大量信息。例如,不僅有基本的產品信息(如名稱、描述和價格),而且此頁面還顯示:

  • 購物車中的商品數量
  • 訂單歷史
  • 顧客評論
  • 低庫存警告
  • 送貨選項
  • 各種推薦,包括經常購買該產品的其他產品,購買該產品的客戶購買的其他產品,以及購買該產品的客戶查看的其他產品
  • 替代購買選項

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

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

  • 購物車服務 - 購物車中的商品數量
  • 訂單服務 – 訂單歷史
  • 目錄服務 - 基本產品信息,例如其名稱、圖像和價格
  • 評論服務 – 客戶評論
  • 庫存服務 - 低庫存警告
  • 運輸服務 – 運輸選項、截止日期和費用,獨立於運輸提供商的 API
  • 推薦服務——推薦項目

我們需要決定移動客戶端如何訪問這些服務。讓我們看看選項。

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

理論上,客戶端可以直接向每個微服務發出請求。每個微服務都有一個公共端點。該 URL 將映射到微服務的負載均衡器,該負載均衡器在可用實例之間分配請求。為了檢索產品詳細信息,移動客戶端將向上面列出的每個服務發出請求。

不幸的是,此選項存在挑戰和限制。一個問題是客戶端的需求與每個微服務公開的細粒度 API 之間的不匹配。此示例中的客戶端必須發出七個單獨的請求。在更複雜的應用程式中,它可能需要做更多的事情。例如,亞馬遜描述了數百種服務如何參與呈現他們的產品頁面。雖然客戶端可以通過 LAN 發出這麼多請求,但在公共 Internet 上可能效率太低,而且在行動網路上肯定不切實際。這種方法還使客戶端代碼更加複雜。

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

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

由於這些類型的問題,客戶直接與微服務對話幾乎沒有意義。

使用 API 網關

通常更好的方法是使用所謂的API Gateway。API 網關是一個伺服器,它是系統的單一入口點。它類似於面向對象設計的外觀模式。API 網關封裝了內部系統架構,並提供了為每個客戶端量身定製的 API。它可能具有其他職責,例如身份驗證、監控、負載平衡、緩存、請求整形和管理以及靜態響應處理。

下圖顯示了 API 網關通常如何適應架構:

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

API 網關還可以為每個客戶端提供自定義 API。它通常為移動客戶端公開一個粗粒度的 API。例如,考慮產品詳細信息場景。API 網關可以提供一個端點,使移動客戶端能夠通過單個請求檢索所有產品詳細信息。API 網關通過調用各種服務(產品信息、推薦、評論等)並組合結果來處理請求。

API 網關的一個很好的例子是Netflix API 網關。Netflix 流媒體服務可在數百種不同類型的設備上使用,包括電視、機頂盒、智慧型手機、遊戲系統、平板電腦等。最初,Netflix 試圖為其流媒體服務提供一刀切的API。然而,他們發現由於設備種類繁多及其獨特的需求,它並不能很好地工作。今天,他們使用 API 網關,通過運行特定於設備的適配器代碼為每個設備提供定製的 API。適配器通常通過平均調用六到七個後端服務來處理每個請求。Netflix 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 引擎構建的平台。另一種選擇是使用NGINX Plus, NGINX Plus 提供成熟、可擴展、高性能的 Web 伺服器和反向代理,易於部署、配置和編程。NGINX Plus 可以管理身份驗證、訪問控制、負載平衡請求、緩存響應,並提供應用程式感知的健康檢查和監控。

使用反應式編程模型

API 網關通過簡略地將它們路由到恰當的後端服務來處理一些請求。它通過調用多個後端服務並聚合結果來處理其他請求。對於某些清求,例如產品詳細信息請求,對後端服務的請求是相互獨立的。為了最小化響應時間,API 網關應當同時履行獨立的請求。但是,有時清求之間存在依賴關聯。API 網關可能首先需要通過調用身份驗證服務來驗證懇求,然後再將懇求路由到後端服務。同樣,如果獲得有關客戶願望清單中產品的信息,API 網關必須首先檢索包含該信息的客戶配置文件,然後檢索每個產品的信息。

使用傳統的異步回調方法編寫 API 組合代碼會很快將您帶入回調地獄。代碼會很糾結,難以理解,而且容易出錯。更好的方法是使用響應式方法以聲明式風格編寫 API Gateway 代碼。響應式抽象的示例包括Scala 中的Future、Java 8 中的[CompletableFuture和 JavaScript 中的Promise。還有反應式擴展(也稱為 Rx 或 ReactiveX),最初由 Microsoft 為 .NET 平台開發。Netflix 為 JVM 創建了 RxJava,專門用於他們的 API 網關。還有用於 JavaScript 的 RxJS,它可以在瀏覽器和 Node.js 中運行。使用反應式方法將使您能夠編寫簡單而高效的 API 網關代碼。

服務調用

基於微服務的應用程式是一個分布式系統,必須使用進程間通信機制。進程間通信有兩種風格。一種選擇是使用基於消息傳遞的異步機制。一些實現使用消息代理,例如 JMS 或 AMQP。其他的,例如 Zeromq,是無代理的,服務直接通信。另一種進程間通信方式是同步機制,例如 HTTP 或 Thrift。系統通常會同時使用異步和同步樣式。它甚至可能使用每種樣式的多個實現。因此,API 網關需要支持多種通信機制。

服務發現

API 網關需要曉得與之通信的每個微服務的位置(IP 地點和埠)。在傳統應用程式中,您可能可以硬連接位置,但在現代、基於雲的微服務應用程式中,這是一個不平常的難題。基礎設施服務,例如消息代理,通常有一個靜態位置,可以通過作業系統環境變量指定。然而,確定應用服務的位置並不容易。應用程式服務具備動態分配的位置。此外,由於自動縮放和升級,服務的實例會議動態變化。因此,API 網關與體系中的任何其他服務客戶端一樣,需要應用體系的服務發現機制:伺服器端發現或客戶端發現。現在,值得注意的是,如果系統應用客戶端發現,那麼 API 網關必須能夠查詢服務註冊表,這是一個包含所有微服務實例及其位置的資料庫。

處理部分故障

實現 API 網關時必須解決的另一個問題是部分失敗的問題。每當一個服務調用另一個響應緩慢或不可用的服務時,所有分布式系統都會出現此問題。API 網關不應該無限期地

實現 API 網關時必須解決的另一個題目是局部失敗的問題。每當一個服務調用另一個響應遲緩或不可用的服務時,所有分布式體系城市出現此問題。API 網關不應當無限期地阻塞等待下游服務。但是,它如何處理失敗取決於具體的場景和失敗的服務。例如,如果推舉服務在產品詳情場景中沒有響應,API 網關應當將其餘的產品詳情返回給客戶端,因為它們對用戶仍然有效。這些提議可以是空的,也可以由例如硬連線的前十名列表調換。但是,如果產品信息服務沒有響應,那麼 API Gateway 該當向客戶端返回一個錯誤。

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

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

概括

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

關鍵字: