1. 程式人生 > >建立微服務-用API閘道器實現

建立微服務-用API閘道器實現

建立微服務-用API閘道器實現

第一篇文章講述了微服務的建立、設計和部署。同時,也討論了關於應用微服務的優點和缺點。雖然微服務結構複雜,但它是處理複雜程式架構的理想選擇。本文講述通過API閘道器構造微服務。

當你選擇採用微服務構建自己的程式,則你需要考慮客戶端怎樣與後端服務互動。對於一個單體應用,僅有一個服務群提供服務(通過負載均衡器實現)。在微服務架構裡面,每一個服務都暴漏了一個伺服器叢集。本篇文章我們討論它對於客戶端通訊的影響和提出通過API閘道器的解決辦法。

背景介紹

首先讓我們想象一下一個購物的移動程式。它需要實現產品詳情頁展示,例如產品資訊、庫存資訊、訂單資訊、購物車等。例如,下圖顯示了你將看到的產品資訊:

 

儘管它僅僅是一個手機程式的詳情頁,它也顯示了產品的一些資訊。它不僅展示了一些產品的基本資訊(名稱、描述和價格),也顯示以下資訊:

1)購物車中的產品數

 2)訂單歷史

 3)客戶瀏覽歷史

4)低庫存預警

5)物流資訊

6)推薦資訊,包括經常購買的新、購買過之後的推薦和瀏覽歷史推薦;

7)不同的購買選項

如果採用單體程式,客戶端僅僅需要一個連結就能夠獲取所需要的所有資訊。負載均衡器返回任何一個應用程式的反饋資料即可。應用程式將會查詢資料表,並向客戶返回資料。

相反,微服務架構下,產品詳情頁資料則需要好幾個服務群才能夠提供。這裡是幾個擁有產品詳情頁資訊資料的幾個伺服器服務:

1)購物車服務-負責顯示購物車中的產品數量

2)訂單服務-訂單歷史

3)類目服務-提供產品的名字、描述和價格

4)歷史服務-使用者的瀏覽歷史

5)庫存服務-低庫存預警

6)物流服務-從物流提供商返回物流花費、到達時間和物流選項

7)推薦服務-建議選項

 

我們需要決定,客戶端怎樣獲取這些服務。下面讓我們討論一下可能的方案。

客戶端直接連線微服務

理論上微服務可以直接連線微服務。每一個微服務都有一個地址,這個地址映射向服務均衡(提供服務的負載)地址。為了獲取產品資訊,客戶端可以直接連線上述的微服務地址。

不幸的,這種方案存在挑戰和限制。其一,其存在客戶端和微服務之間的錯配問題。客戶端不得不發起其次獨立的請求。在複雜的系統,它需要返回更多的請求。例如,亞馬遜在選擇頁面的時候描述了數百個微服務。如果客戶端發起了過多的請求,會導致

網際網路的低效,這也不是行動網路的最佳實踐。這也會導致客戶端的過度複雜。(個人覺得,如果微服務頁面較少,這會提升開發效率和網路請求時間)

直連的另一個問題是微服務對外的協議可能不是web友好的。例如,有些服務採用Thrift binary RPC,而有些則採用AMQP 。這兩種協議都不是瀏覽器和防火牆所友好的協議。一個友好的web協議應該採用WebSocket 或者HTTP協議。

另一個缺陷是這種解決方案使得重構微服務變得困難。隨著時間改變,我們想改變微服務劃分的標準。例如,我們可能將兩個微服務合併,或者拆分一個微服務。這種型別的重構將會使得這種方案變得非常困難。

採用API閘道器

通常,一個較好的方案採用API閘道器。API閘道器是一種從前端到後端的唯一路徑服務。它類似於面向物件設計的Facade 模式。API閘道器將後端的服務進行了包裝,同時提供了客戶端所需要的API。它還提供其他職責,像許可權、監控、負載均衡、快取、請求轉發和管理、靜態請求處理等。

以下圖展示了API閘道器適應的架構:

 

API閘道器負責請求的路由轉發、組合和協議解釋。所有來自客戶端的請求都需要經過API閘道器。它將請求匹配到合適的微服務。它通過請求多個微服務或者聚合結果處理請求。它能夠在HTTP、WebSocket和不友好的協議之間轉換。

API閘道器也為客戶端提供個性化的介面。它為移動客戶端提供了粗粒度的API。例如,產品的詳情頁。例如,他能夠為移動客戶端提供一個連線,通過此可以獲得所有的所需資料。API閘道器處理請求分為兩步:1)向不同的服務請求資料 2)合併資料。

API閘道器的一個成功例子是Netflix API Gateway Netflix流服務包含數百種終端裝置,像電視、行動電話、遊戲等。Netflix向提供一種統一形式的API。但是,他們發現由於涵蓋的裝置太多和個性化需求導致這種方案太難實現。現在,他們為每種型別的裝置實現一種裝置適配,通過API閘道器做具體適配。一種適配通過呼叫六、七種服務處理請求。The Netflix API Gateway每天處理數十億請求。

API閘道器的優缺點

正如期望的那樣,API閘道器也存在優點和缺點。最大的優勢是API閘道器遮蔽了後端服務的結構。客戶可以簡單的通訊,而不用處理服務之間的關係。API閘道器為每種客戶端提供單獨的介面。它減少了客戶端和應用程式之間的往返次數。它也簡化了客戶端的程式碼。

API閘道器也有缺陷。它必須是一個開發、設計和部署的高可用組建。API閘道器成為開發的瓶頸是一種風險。研發必須升級閘道器服務以便暴露所有的服務。儘可能的輕量化部署API閘道器非常重要。開發者發版時必須要線性等待。儘管有這些缺點,程式採用API閘道器將會是有意義的。

個人認為:在程式框架的前期當服務並不是很多的時候,可以嘗試採用客戶端直連的形式實現,但是前端必須建立前端路由。如果後期服務較多,則儘量採用API路由閘道器的形式,因為這種情況下可以縮短請求次數、縮短請求路徑,此種問題的請求不包含靜態檔案的處理。

實現API閘道器

現在我們已經瞭解了建立API閘道器的目的和意義了。讓我們看一下建立時需要考慮的事情:

效能和伸縮性

僅有很少的公司如Netflix一樣伸縮操作和單日處理數十億請求。但是,API閘道器的效能和伸縮性非常重要。在一個平臺上建立一個非同步、非阻塞的IO API閘道器是由意義的。有多重技術實現API閘道器的自由伸縮。在JVM上,你可以實現基於NIO框架的程式,類似於 Netty, Vertx, Spring Reactor, or JBoss Undertow。一個流行的費JVM技術是Node.js,它建立在Chrome的javascr上.另一個解決方案是 NGINX Plus.,它提供了生出的伸縮、高效能Web服務和易於建立、配置和程式設計的反向代理。

NGINX Plus.能夠提供管理許可權、獲得控制、負載請求、快取處理結果和提供心跳感知和監控。

採用自適應程式設計模型

API閘道器通過簡單的路由請求到不同的服務處理客戶端請求。它通過引用多個後端服務和聚合結果來處理其他服務。一些請求像請求產品詳情的請求獨立與其他請求。為了最小化請求,API閘道器需要並行處理請求。有時,不同請求之間存在依賴。AIP閘道器在處理請求之前,可能首先驗證服務請求。類似的,為了獲取與客戶相關的產品列表資訊,可能首先獲取使用者資訊,其次獲取相關的產品資訊。API元件的例子是Netflix Video Grid.。

如果採用傳統的非同步請求程式碼變下API閘道器,可能會進行請求地獄。這些程式碼非常難寫、難於理解和易錯。寫這種程式碼的一種較好辦法是採用反應法以一種清晰的樣式書寫。適應抽象的例子包括Future in Scala, CompletableFuture in Java 8, and Promise in JavaScript. There is also Reactive Extensions (also called Rx or ReactiveX)。

服務呼叫

微服務程式是一個分散式的程式,但是必須提供程序間通訊的機制。在程序間通訊有兩種形式。一種是非同步的、基於訊息的通訊。一些實現採用訊息代理例如JMS or AMQP。還有不採用代理的,如 Zeromq(這種訊息直接通訊)。另一種是直接通訊,像HTTP or Thrift。一個系統會用同步或者非同步通訊。一種形式會有多種的實現形式。因此,API閘道器需要實現多種通訊機制。

服務發現

API閘道器知道相互通訊服務的地址。在傳統系統,你可能硬編碼地址,但是在現代雲服務平臺這將是一個巨大的問題。基礎服務,像訊息代理,可以通過系統變數設定,但是固定一個程式服務地址並不可行。因為一個應用程式服務的地址是動態指定的,同時服務隨著伸縮或者更新,地址也可能會發生改變。因此,API閘道器就像其他客戶端程式一樣,需要應用系統的服務發現功能:服務端發現和客戶端發現。

處理區域性報錯

另一個你需要關注的問題是區域性報錯問題。這個問題發生在一個服務呼叫另一個服務時,導致的原因是服務慢或者服務不可用。API閘道器永遠不要無限制的阻塞服務呼叫。具體怎麼處理依賴於具體的場景和哪個服務失敗。例如,如果推薦服務報錯,則API閘道器需要將產品的其他資訊返回給客戶端,因為這些資訊依然對於客戶有用。如果產品資訊不再服務,則需要向用戶返回報錯資訊。

API閘道器應該返回在條件允許的情況下,應該返回快取資訊。例如,產品價格不頻繁改動,如果產品價格服務不可用,則應該返回快取中的產品價格。資料應該快取在API伺服器記憶體或者第三方內容中如Reddis或者memcached。通過返回預設資訊或者快取資訊,API閘道器保證系統錯誤不影響使用者體驗。

Netflix Hystrix 是一個有用遠端服務引用庫。Hystrix 採用呼叫超時策略。它採用斷路模式,即阻止客戶端等待呼叫不反應的服務。如果某個服務發生錯誤的次數超過閾值,則Hystrix 啟動斷路並不允許客戶端繼續呼叫該服務。Hystrix定義了一個包括返回呼叫機制,報錯後允許你獲取快取或者預設資料。

總結

對於大多數的微服務程式,採用API閘道器(作為程式的單一訪問點)是有意義的。API閘道器負責請求路由、組合請求結果和協議解析。它為每種程式的客戶端提供的單獨的介面。它通過獲取記憶體或者預設值可以掩蓋後端錯誤。但是其路由的構建、結果的合併將是核心。