Chris Richardson 微服務系列翻譯全7篇鏈接:
- 微服務介紹
- 構建微服務之使用API網(wǎng)關(本文)
- 構建微服務之微服務架構的進程通訊
- 微服務架構中的服務發(fā)現(xiàn)
- 微服務之事件驅動的數(shù)據(jù)管理
- 微服務部署
- 重構單體應用為微服務
原文鏈接:Building Microservices: Using an API Gateway
介紹
假設我們?yōu)橐粋€商品應用開發(fā)一個移動APP陆错,我們應該提供一個產(chǎn)品詳情頁來展示指定產(chǎn)品的信息何缓。Amazon Android 應用在商品詳情頁展示的內容,如下圖所示:
盡管只是移動APP败明,商品詳情頁依然展示給我們很多信息,不僅包括基本信息(名稱太防、描述妻顶、價格),還包含如下內容:
- 購物車中的商品數(shù)
- 歷史訂單記錄
- 買家評價
- 低庫存預警
- 送貨選項
- 推薦:包括與此商品一起購買的其他商品蜒车、購買該商品的顧客還買的其他商品讳嘱、購買該商品的顧客還看過其他的商品
- 其他購物選項
使用單體應用架構時,移動APP通過單一的 REST 請求(GET api.company.com/productdetails/productId)來獲取展示的數(shù)據(jù)酿愧。負載均衡會將請求路由到多個相同實例的其中一個沥潭,然后程序查詢各種數(shù)據(jù)庫表,返回數(shù)據(jù)給客戶端嬉挡。
對應如果采用微服務架構钝鸽,展示在產(chǎn)品詳情頁的數(shù)據(jù)會來自不同的微服務上汇恤。下面列舉一些微服務對應的展示數(shù)據(jù):
- 購物車服務:購物車中的商品數(shù)
- 訂單服務:訂單記錄
- 目錄服務:商品基本信息,如名稱拔恰、圖片和價格
- 評論服務:用戶評價
- 庫存服務:低庫存預警
- 配送服務:送貨選項因谎、期限和費用
- 推薦服務:推薦商品
客戶端如何訪問這些服務,讓我們看看下面的方法颜懊。
客戶端與服務端直接通信
理論上客戶端可以直接請求每個微服務财岔,每個微服務都有一個公開的節(jié)點(https://serviceName.api.company.com),該 URL 映射到負載均衡河爹,然后被分發(fā)到可用的實例上處理匠璧,為了獲取產(chǎn)品詳情,移動客戶端需要向上述每個服務發(fā)送請求咸这。
遺憾的是夷恍,這種方法存在挑戰(zhàn)和局限:
1)客戶端需求和每個微服務暴露出的細粒度 API 不匹配。本例中客戶端需要發(fā)送7個不同的請求媳维,在一個復雜的應用中請求數(shù)甚至還要更多酿雪,例如亞馬遜在顯示他們的產(chǎn)品頁面時會調用數(shù)百個服務。這種方法還使得客戶端代碼非常復雜侨艾。
2)一些服務使用的協(xié)議對 web 并不友好执虹。一個服務可能使用 Thrift 的二進制 RPC,而另一個服務可能使用 AMQP 消息協(xié)議唠梨。這些協(xié)議不是瀏覽器和防火墻友好的袋励,最好在內部使用。而防火墻之外当叭,應用程序最好使用 HTTP 或 WebSocket 之類的協(xié)議茬故。
3)這種方法會使得微服務難以重構。隨著時間的推移蚁鳖,我們可能要重新規(guī)劃磺芭、合并或拆分微服務,如果客戶端直接與微服務通信的話醉箕,對這些微服務進行重構變得異常困難钾腺。
正是這些原因,采用客戶端直接調用微服務的方式并不明智讥裤。
使用 API 網(wǎng)關
通常更好的方式是使用 API 網(wǎng)關放棒,API 網(wǎng)關是提供系統(tǒng)唯一入口的服務器,他和設計模式中的 外觀模式 類似:API 網(wǎng)關封裝內部系統(tǒng)架構己英,并向客戶端提供 API间螟。它還可能負責諸如 用戶驗證、監(jiān)控、負載均衡厢破、緩存荣瑟、請求管理、靜態(tài)響應處理等功能摩泪。下圖展示了適應 API 網(wǎng)關的架構:
API 網(wǎng)關負責請求路由笆焰、組合和協(xié)議轉換。來自客戶端的所有請求都先經(jīng)過 API 網(wǎng)關加勤,然后被路由到對應的微服務中仙辟,API 網(wǎng)關通常調用多個微服務并聚合其結果來處理請求同波。它可以在 web 協(xié)議(如 HTTP 和 WebSocket)與內部使用的非 web 協(xié)議之間轉換鳄梅。
API 網(wǎng)關可以為每個客戶端提供定制的 API,它通常為移動客戶端暴露粗粒度的 API未檩。例如:商品詳情頁戴尸,API 網(wǎng)關提供 (/productdetails?productid=xxx) 節(jié)點使得移動客戶端單一請求可以獲取所有的產(chǎn)品明細。API 網(wǎng)關調用各個服務(商品信息冤狡、推薦孙蒙、評論等)合并結果并返回。
Netflix API網(wǎng)關 就是一個很好的 API 網(wǎng)關實例悲雳。Netflix 流媒體服務提供給成百上千的設備使用挎峦,包括電視、機頂盒合瓢、智能手機坦胶、游戲系統(tǒng)、平板電腦等晴楔。最初顿苇,Netflix 視圖為他們的流服務提供通用的 API,然而税弃,他們發(fā)現(xiàn)由于設備的獨特需求纪岁,這種設計方式不能很好的工作。如今他們使用 API 網(wǎng)關通過運行設備的適配器代碼為客戶端提供定制的 API则果,通常適配器為每個請求平均調用6~7個微服務幔翰,Netflix API網(wǎng)關每天處理數(shù)十億請求。
使用 API 網(wǎng)關的優(yōu)勢及劣勢
使用 API 網(wǎng)關有優(yōu)勢也有不足西壮。
最大優(yōu)點是:
1)它封裝了應用的內部結構遗增,客戶端只需要簡單的與 API 網(wǎng)關交互即可,而不用直接調用每個服務茸时。
2)API 網(wǎng)關為不同的客戶端提供定制的 API贡定,減少了客戶端和應用間的交互次數(shù),并大大簡化了客戶端的代碼可都。
API 網(wǎng)關也有其不足:
1)它本身增加了一個需要開發(fā)缓待、部署和維護的高可用組件蚓耽。
2) API 網(wǎng)關有時候變成了開發(fā)的瓶頸。開發(fā)者為了暴露新的微服務必須更新 API 網(wǎng)關旋炒。API 網(wǎng)關的更新流程要盡可能的簡單步悠,否則,開發(fā)人員不得不排隊等待瘫镇。盡管它有這些不足鼎兽,但對于大部分的應用程序而言,使用 API 網(wǎng)關是合理的铣除。
實現(xiàn)一個 API 網(wǎng)關
目前我們討論了 API 網(wǎng)關的動機和一些優(yōu)缺點谚咬。下面我們看一些需要考慮的一些設計問題。
性能與擴展性
只有少數(shù)公司擁有 Netflix 這樣的規(guī)模尚粘,每天需要處理數(shù)十億的請求择卦。對于大多數(shù)程序而言,API 網(wǎng)關的性能和可擴展性是非常重要的郎嫁。因此秉继,API 網(wǎng)關構建在一個支持異步、IO 非阻塞的平臺上是合理的泽铛。有多種不同的技術可參考:JVM 上尚辑,基于 NIO 的框架,比如 Netty盔腔、Vertx杠茬、 Spring Reactor 或 JBoss Undertow 等。一個流行的選項是 Node.js铲觉,他是構建于 Chrome JS 引擎的平臺澈蝙。另一個選項是 NGINX Plus,他提供了成熟撵幽、可擴展灯荧、高性能的 web 服務器和一個易于部署的、可配置可編程的反向代理盐杂。NGINX Plus 可以管理身份驗證逗载、權限控制、負載均衡链烈、緩存以及應用級別的健康檢查及監(jiān)控厉斟。
使用響應式編程模型
API 網(wǎng)關將請求路由到相應的多個微服務并合并處理結果,對于一些請求强衡,例如產(chǎn)品詳情頁擦秽,后端對應的服務是彼此獨立的,為了減少響應時間,API 網(wǎng)關應并行處理這些請求感挥。然而有時候缩搅,請求之間是有依賴關系的,在請求微服務之前触幼,API 網(wǎng)關需要調用身份驗證服務來驗證請求的合法性硼瓣。類似的,獲取用戶心愿單上的產(chǎn)品信息時置谦,API 網(wǎng)關需要先獲取包含這些信息的客戶資料堂鲤,然后再去獲取信息的詳情。另一個有趣的例子就是:Netflix Video Grid媒峡。
使用傳統(tǒng)的異步回調方式來寫 API 組合代碼會把你帶入地獄瘟栖。代碼會變的混亂、難以理解且容易出錯丝蹭。更好的方式是使用響應式方法慢宗,以一種聲明式樣式編寫 API 網(wǎng)關代碼坪蚁。例如:Scala中的 Future 奔穿、Java 8中的CompletableFuture 以及JavaScript中的Promise ,還有微軟為.NET開發(fā)的Reactive Extensions敏晤。Netflix 為他們的 API 網(wǎng)關創(chuàng)建了 RxJava for JVM贱田,此外還有 RxJS for JavaScript,既可以在瀏覽器中運行嘴脾,也可以在Node.js 中運行男摧。響應式風格將幫助你寫出簡潔高效的 API 網(wǎng)關代碼。
服務調用
微服務架構是一個進程間通信的分布式系統(tǒng)译打, 有兩種進程間通信方式:一種是采用異步耗拓、基于消息傳遞的機制。例如:JMS 或 AMQP 這樣的消息組件奏司;另一種是使用 HTTP 或 Thrfit 這種同步機制進行通信乔询。通常,一個系統(tǒng)會同時使用同步和異步方式韵洋,甚至還會使用同一類型的多種實現(xiàn)竿刁。總之搪缨,API 網(wǎng)關需要支持不同的通信機制食拜。
服務發(fā)現(xiàn)
API 網(wǎng)關需要知道和他通信的每個微服務的地址(IP和端口號)。傳統(tǒng)應用中副编,可以使用硬編碼的方式负甸,但是在現(xiàn)代基于云的微服務應用中,這不是一個容易解決的問題∩氪基礎架構服務(例如:消息組件)通常會有一個靜態(tài)地址煮盼,可以在環(huán)境變量中指定。然而带污,獲取一個微服務地址就不是簡單的事了僵控,微服務的地址是動態(tài)分配的,一組服務實例可能因為自動擴展或升級而動態(tài)的變化鱼冀。因此 API 網(wǎng)關需要服務發(fā)現(xiàn)機制报破,可以是服務器端發(fā)現(xiàn),或者是客戶端發(fā)現(xiàn)(后面的文章會詳細介紹服務發(fā)現(xiàn)的問題)千绪。如果使用客戶端發(fā)現(xiàn)的話充易,API 網(wǎng)關應該能查詢服務注冊中心,這是一個包含所有微服務實例及其地址的數(shù)據(jù)庫荸型。
處理局部故障
局部故障在分布式系統(tǒng)中很常見盹靴,當一個服務調用另一個服務,當后者響應慢或不可用時就出現(xiàn)了這個問題瑞妇。API 網(wǎng)關不能因為無限期的等待下游服務而阻塞稿静。不過,如何處理失敗取決于應用場景或具體哪個服務失敗辕狰,例如:產(chǎn)品詳情頁改备,推薦服務掛了,那么 API 網(wǎng)關應該返回其他產(chǎn)品信息蔓倍,保障產(chǎn)品對用戶仍然可用悬钳,推薦內容可為空或使用固定的 Top 10 列表取代。不過偶翅,如果產(chǎn)品服務掛了默勾,那么 API 網(wǎng)關應該返回客戶端錯誤信息。
API 網(wǎng)關也可以緩存返回的數(shù)據(jù)聚谁。例如:產(chǎn)品價格變動不頻繁母剥,當價格服務不可用時,API 網(wǎng)關可以返回緩存的價格數(shù)據(jù)垦巴。數(shù)據(jù)可以是 API 網(wǎng)關自己緩存媳搪,也可以使用 Redis 或 Memcached之類的外部緩存。通過返回默認值或緩存值骤宣,API 網(wǎng)關保證局部故障不會影響用戶體驗秦爆。
Netflix Hystrix 在編寫代碼調用遠程服務時是非常有用的,Hystrix 會標記超過特定閥值的調用為超時憔披,他還實現(xiàn)了『熔斷器』模式來防止對無響應服務的更多請求等限,如果一個服務的出錯率超過了特定閥值爸吮,那么 Hystrix 會觸發(fā)熔斷器,所有請求會快速失敗并持續(xù)一段時間望门。Hystrix 允許用戶定義請求失敗時的 fallback 操作形娇,例如:讀取緩存或返回默認值。如果你在使用 JVM 筹误,那么應該考慮使用 Hystrix桐早,如果使用的是非 JVM 環(huán)境,那么可以使用一個功能相同的庫厨剪。
總結
對于大部分基于微服務的應用哄酝,實現(xiàn) API 網(wǎng)關作為應用的單一入口是明智的。API 網(wǎng)關負責請求路由祷膳、聚合陶衅、協(xié)議轉換。為每個客戶端提供特定的 API直晨,還可以通過返回默認值或緩存值來處理后端服務的調用失敗搀军。下篇文章,我們將討論服務間的通信勇皇。