2.使用API網關構建微服務

本文出自Nginx官網,是微服務介紹系列文章的第二篇。

原文地址:https://www.nginx.com/blog/building-microservices-using-an-api-gateway/

1. 介紹

當我們使用微服務構建應用時,需要考慮客戶端如何和應用通信。對於單體應用而言,只有一組實例(一般是負載均衡加上多個應用副本);而在微服務架構下,每個服務都可能有一組實例。在本篇文章中,我們將看到這如何影響客戶端和服務的通信,將看到如何應用API網關解決問題。

假設我們要開發一個原生的手機購物應用,有一個頁面要展示詳細的商品信息,展示效果如下圖所示:


除了展示商品的基本信息(像名稱、描述和價格等),還包含以下信息:

A. 購物車中的商品數

B. 歷史訂單

C. 用戶評價

D. 低庫存告警

E. 物流選項

F. 智能推薦

G. 替代產品

對於單體應用而言,手機客戶端只需要發送一次請求(像:GET api.company.com/productdetails/productId),負載均衡模塊將請求分發到應用實例,應用查詢不同的數據表獲取數據,再將響應返回給客戶端。

對於微服務應用而言,商品詳情頁需要的數據由多個微服務擁有,例如:

購物車服務,提供購物車中的商品數量;

訂單服務,提供歷史訂單;

商品分類服務,提供商品名稱、圖片、價格等商品基本信息;

評價服務,提供用戶評價;

庫存服務,提供低庫存警告;

物流服務,提供物流選擇、到貨日期以及物流價格等;

推薦服務,提供智能推薦的關聯商品。


我們需要考慮手機客戶端如何訪問這些服務。

2. 客戶端直接訪問微服務

理論上說,客戶端可以直接訪問微服務。每個微服務都會發佈一個公共訪問入口(像:https://serviceName.api.company.name),這個鏈接指向微服務的負載均衡模塊。爲了獲取商品詳情的各種數據,手機客戶端需要訪問多個相關的微服務。

不幸的是,由客戶端直接訪問微服務有很多限制和挑戰。其中一個問題是客戶端的需求和微服務提供的接口不匹配。在商品詳情的例子中,客戶端需要訪問多個微服務,多個微服務組合的纔是客戶端想要的。應用越複雜,需要訪問的微服務就越多,Amazon展示商品詳情時需要訪問上百個服務。客戶端通過互聯網和移動網絡訪問這麼多服務顯得效率低下,還會造成客戶端代碼特別複雜。

客戶端直接訪問微服務的另外一個問題是,有些微服務提供的接口並不是Web友好的,一個服務可能使用Thrift的RPC,而另外一個服務可能使用AMQP的消息機制;這些服務都不是防火牆友好的,並不是互聯網上的最佳實踐。一個應用應該在防火牆外使用HTTP和WebSocket這些對Web友好的通信協議。

最後一個問題是,客戶端直接訪問微服務會導致微服務重構困難。隨着時間的推移,我們可能會對原有服務進行拆分或合併等重構工作,而如果客戶端直接訪問微服務,這些重構工作會不可避免的影響到客戶端,從而使得重構變得異常困難。

由於以上原因,客戶端直接訪問微服務不可行。

3. 使用API網關

API網關是一種較好的客戶端訪問微服務的方式。API網關是系統的單一訪問入口,就像面向對象設計模式中的Façade模式,它隱藏了應用的內部結構,爲不同類型的客戶端定製不同接口。API網關還能提供鑑權、監視、負載均衡、緩存、協議轉換和管理等功能。下圖展示了本例中API網關的結構:


API網關負責請求路由、響應組裝和協議轉換。所有的客戶端請求先到API網關,網關將請求路由到對應的微服務;在客戶端的一次請求中,網關可能調用多個微服務,再將多個返回結果組裝後返回給客戶端。API網關還能實現Web協議(Http、WebSocket)與其他協議的轉換。

API網關能爲每一類客戶端定製接口。比如它能爲手機客戶端定製商品詳情的接口(/productdetails?productid=xxx),手機客戶端調用這個接口獲取商品詳情頁的所有信息。

Netflix的API網關是個典型的例子,Netflix的流視頻服務在電視、電視盒子、智能手機、遊戲機等上百種不同的設備上都能使用。最初,Netflix努力設計能適用於所有設備的統一接口,後來發現不同設備對接口的需求差異太大。今天,Netflix通過API網關使用不同的設備適配器爲每種設備提供不同的接口,每種設備適配器調用6到7個微服務。每天Netflix的API網關處理上百萬次的客戶端請求。

4. API網關的優點和缺點

最大的優點是API網關封裝了應用的具體實現,簡化了客戶端與應用之間的通信,極大減少了客戶端的代碼量。

缺點是你需要開發、部署、管理一個高可靠的API網關。由於所有的請求都先到API網關,它很可能變成整個系統的瓶頸;另外API網關要足夠輕量級,要方便升級以反映微服務的變化。雖然有上述缺點,API網關對大多數現實中的應用來說還是一種可行的微服務實現方案。

5. 實現API網關

現在我們來看實現API網關時需要重點考慮的幾個問題:

性能和伸縮性

         全世界只有大約100個像Netflix那樣規模的應用,每天需要處理百萬級的服務請求。你的應用規模可能沒有那麼大,可API網關的性能和伸縮性依然很重要。因此,在支持異步調用、非阻塞I/O等高性能特性的平臺上構建API網關就很重要。在JVM之上,你可以使用基於NIO的框架,像Netty、Vertx、Spring Reactor或者JBoss Undertow;另外一種非JVM的選項是基於Chrome的js引擎Node.js;還有一種選擇是Nginx Plus。Nginx Plus可作爲成熟的、可伸縮的、高性能的web服務器和反向代理服務器,部署簡單,配置和編程方便,並能支持身份鑑別、訪問控制、負載均衡、服務健康檢查等功能。

使用響應式編程模型

對有些服務請求,API網關簡單轉發;對另外一些服務請求,API網關需要調用幾個服務,並組裝多個服務的響應。對於某些服務請求,像之前講到的商品詳情,需要調用多個互相獨立的服務;爲了縮短服務響應時間,API網關應該支持併發多個服務請求;而有些時候,服務之間可能有依賴,比如需要先進行身份鑑別再調用服務。類似的,要展示用戶心願列表中的商品詳情,需要先獲取用戶的心願列表,再根據心願列表獲取每件商品的詳細信息。另外一個有趣的服務組合示例是Netflix的視頻網格。

使用傳統異步調用方式編寫服務組合的代碼會是一場災難,代碼會變得雜亂、不易理解、容易出錯。一個更好的方式是使用響應式編程編寫聲明式代碼,現在很多語言都支持響應式的抽象,像Scala中的Future、Java8中的CompletableFuture、JaveScript中的Promise。還有一些響應式的擴展(也叫Rx或者ReactiveX),這最早是微軟爲.Net平臺開發的,後來Netflix爲他們的API網關開發了RxJava,現在針對瀏覽器和Node.js有了RxJS。使用響應式編程可以讓你書寫簡單高效的API網關代碼。

服務調用

基於微服務的應用是分佈式系統,必須使用進程間通信的機制。進程間通信主要有兩大類,其中一種基於消息的異步調用,使用類似JMS、AMQP等消息中間件,或者像Zeromq這種不需要消息中間件的服務間直接通信;另外一種是像Http和Thrift之類的同步調用。這兩種通信機制,在應用中一般都會用到,甚至會組合使用。因此,使用API網關實現微服務架構時,需要支持多種服務間通信機制。

服務發現

         API網關需要知道跟它通信的所有微服務的訪問入口(IP地址加端口號)。在傳統的單體應用中,直接將IP地址和端口號硬編碼到應用中就可以,而在基於微服務的應用中就不行了。提供基礎設施的服務(像消息中間件)還可以通過配置環境變量事先確定,而應用的其他服務的訪問入口是動態變化的。另外,由於自動伸縮特性和服務實時更新,構成服務的實例的集合也是動態變化的。因此,API網關像其他服務客戶端一樣,需要使用系統的服務發現機制(服務端發現或者客戶端發現),後續會有文章專門描述服務發現。需要指出的是,如果系統採用客戶端服務發現機制,那API網關必須能查詢服務註冊表(包含所有服務實例和訪問入口的數據庫)。

處理部分失敗

         另外一個必須考慮的問題是部分失敗。在分佈式系統中,一個服務調用另外一個反應遲鈍或者不可達的服務時,就會出現部分失敗的情況。如何處理服務調用失敗要看具體情況,比如說,在展示商品詳情時調用智能推薦服務失敗,API網關就應該展示其他商品信息,因爲這些信息對用戶依然有價值,智能推薦可以是空,或者是默認的top10最受歡迎商品;但是,如果調用商品信息服務失敗,API網關就應該返回錯誤。

         API網關也能返回緩存數據。比方說,既然商品價格不會經常變化,就可以在調用價格服務失敗時返回之前緩存的價格數據;可以使用API網關自身緩存,也可以使用像Redis或Memcached等第三方緩存。通過返回默認數據或者緩存數據,API網關可以確保部分系統失敗不影響用戶體驗。

         NetflixHystrix對編寫遠程服務調用的代碼而言是一個特別有用的庫,它會終止超過閾值的服務調用。它實現了一種斷路器模式,停止客戶端對沒有響應的服務做無意義的等待;如果某一個服務出錯的概率達到閾值,Hystrix會將該服務阻斷,這樣在一定時間內,所有對該服務的請求會立即返回錯誤。Hystrix允許你爲錯誤設置回調操作,在回調操作中可以讀取緩存或者是返回默認值。如果你的應用使用JVM,一定要考慮使用Hystrix;如果你的應用使用沒有JVM的環境,你也應該考慮找一個類似的庫。

6、總結

         對於大多數基於微服務的架構而言,使用API網關是有意義的,它可以作爲應用的單一訪問入口。API網關負責請求路由、響應組裝和協議轉換,它能爲每一類客戶端定製接口;API網關還能標註出錯的服務,並返回默認值或者緩存數據。在接下來的章節中,我們將詳細討論服務間通信。

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