本文講的是<b>微服務實戰(二):使用API Gateway</b>,【編者的話】本系列的第一篇介紹了微服務架構模式。它讨論了采用微服務的優點和缺點,除了一些複雜的微服務,這種模式還是複雜應用的理想選擇。
當你決定将應用作為一組微服務時,需要決定應用用戶端如何與微服務互動。在單體式程式中,通常隻有一組備援的或者負載均衡的服務提供點。在微服務架構中,每一個微服務暴露一組細粒度的服務提供點。在本篇文章中,我們來看它如何影響用戶端到服務端通信,同時提出一種API Gateway的方法。
假定你正在為線上購物應用開發一個原生手機用戶端。你需要實作一個産品最終頁來展示商品資訊。
例如,下面的圖展示了你在亞馬遜Android用戶端上滑動産品最終頁時看到的資訊。

雖然這是一個智能手機應用,這個産品最終頁展示了非常多的資訊。例如,不僅這裡有産品基本資訊(名字、描述和價格),還有以下内容:
購物車中的物品數
下單曆史
使用者評論
低庫存警告
快遞選項
各式各樣的推薦,包括經常跟這個物品一起被購買的産品、購買該物品的其他顧客購買的産品以及購買該産品的顧客還浏覽了哪些産品。
可選的購物選項
當采用一個單體式應用架構,一個移動用戶端将會通過一個REST請求(GET api.company.com/productdetails/productId)來擷取這些資料。一個負載均衡将請求分發到多個應用執行個體之一。應用将查詢各種資料庫并傳回請求給用戶端。
相對的,若是采用微服務架構,最終頁上的資料會分布在不同的微服務上。下面列舉了可能與産品最終頁資料有關的一些微服務:
購物車服務 -- 購物車中的物品數
下單服務 -- 下單曆史
分類服務 -- 基本産品資訊,如名字、圖檔和價格
評論服務 -- 使用者評論
庫存服務 -- 低庫存警告
快遞服務 -- 快遞選項、截止時間、來自不同快遞API的成本計算
推薦服務 -- 推薦産品
我們需要決定移動用戶端如何通路這些服務。請看下面這幾種方式
不幸的是,這個方案有很多困難和限制。其中一個問題是用戶端的需求量與每個微服務暴露的細粒度API數量的不比對。如圖中,用戶端需要7次單獨請求。在更複雜的場景中,可能會需要更多次請求。例如,亞馬遜的産品最終頁要請求數百個微服務。雖然一個用戶端可以通過LAN發起很多個請求,但是在公網上這樣會很沒有效率,這個問題在移動網際網路上尤為突出。這個方案同時會導緻用戶端代碼非常複雜。
另一個存在的問題是用戶端直接請求微服務的協定可能并不是web友好型。一個服務可能是用Thrift的RPC協定,而另一個服務可能是用AMQP消息協定。它們都不是浏覽或防火牆友好的,并且最好是内部使用。應用應該在防火牆外采用類似HTTP或者WEBSocket協定。
這個方案的另一個缺點是它很難重構微服務。随着時間的推移,我們可能需要改變系統微服務目前的切分方案。例如,我們可能需要将兩個服務合并或者将一個服務拆分為多個。但是,如果用戶端直接與微服務互動,那麼這種重構就很難實施。
由于上述三種問題的原因,用戶端直接與伺服器端通信的方式很少在實際中使用。
通常來說,一個更好的解決辦法是采用API Gateway的方式。API Gateway是一個伺服器,也可以說是進入系統的唯一節點。這跟面向對象設計模式中的Facade模式很像。API Gateway封裝内部系統的架構,并且提供API給各個用戶端。它還可能有其他功能,如授權、監控、負載均衡、緩存、請求分片和管理、靜态響應處理等。下圖展示了一個适應目前架構的API Gateway。
API Gateway負責請求轉發、合成和協定轉換。所有來自用戶端的請求都要先經過API Gateway,然後路由這些請求到對應的微服務。API Gateway将經常通過調用多個微服務來處理一個請求以及聚合多個服務的結果。它可以在web協定與内部使用的非Web友好型協定間進行轉換,如HTTP協定、WebSocket協定。
API Gateway可以提供給用戶端一個定制化的API。它暴露一個粗粒度API給移動用戶端。以産品最終頁這個使用場景為例。API Gateway提供一個服務提供點(/productdetails?productid=xxx)使得移動用戶端可以在一個請求中檢索到産品最終頁的全部資料。API Gateway通過調用多個服務來處理這一個請求并傳回結果,涉及産品資訊、推薦、評論等。
如你所料,采用API Gateway也是優缺點并存的。API Gateway的一個最大好處是封裝應用内部結構。相比起來調用指定的服務,用戶端直接跟gatway互動更簡單點。API Gateway提供給每一個用戶端一個特定API,這樣減少了用戶端與伺服器端的通信次數,也簡化了用戶端代碼。
API Gateway也有一些缺點。它是一個高可用的元件,必須要開發、部署和管理。還有一個問題,它可能成為開發的一個瓶頸。開發者必須更新API Gateway來提供新服務提供點來支援新暴露的微服務。更新API Gateway時必須越輕量級越好。否則,開發者将因為更新Gateway而排隊列。但是,除了這些缺點,對于大部分的應用,采用API Gateway的方式都是有效的。
既然我們已經知道了采用API Gateway的動機和優缺點,下面來看在設計它時需要考慮哪些事情。
一個基于微服務的應用是一個分布式系統,并且必須采用線程間通信的機制。有兩種線程間通信的方法。一種是采用異步機制,基于消息的方法。這類的實作方法有JMS和AMQP。另外的,例如Zeromq屬于服務間直接通信。還有一種線程間通信采用同步機制,例如Thrift和HTTP。事實上一個系統會同時采用同步和異步兩種機制。由于它的實作方式有很多種,是以API Gateway就需要支援多種通信方式。
在實作API Gateway過程中,另外一個需要考慮的問題就是部分失敗。這個問題發生在分布式系統中當一個服務調用另外一個服務逾時或者不可用的情況。API Gateway不應該被阻斷并處于無限期等待下遊服務的狀态。但是,如何處理這種失敗依賴于特定的場景和具體服務。例如,如果是在産品詳情頁的推薦服務子產品無響應,那麼API Gateway應該傳回剩下的其他資訊給使用者,因為這些資訊也是有用的。推薦部分可以傳回空,也可以傳回固定的頂部10個給使用者。但是,如果是産品資訊服務無響應,那麼API Gateway就應該給用戶端傳回一個錯誤。
在緩存有效的時候,API Gateway應該能夠傳回緩存。例如,由于産品價格變化并不頻繁,API Gateway在價格服務不可用時應該傳回緩存中的數值。這類資料可以由API Gateway自身來緩存,也可以由Redis或Memcached這類外部緩存實作。通過傳回緩存資料或者預設資料,API Gateway來確定系統錯誤不影響到使用者體驗。
對于大多數微服務基礎的應用,實作一個API Gateway都是有意義的,它就像是進入系統的一個服務提供點。API Gateway負責請求轉發、請求合成和協定轉換。它提供給應用用戶端一個自定義的API。API Gateway可以通過傳回緩存或者預設值的方式來掩蓋後端服務的錯誤。在本系列的下一篇文章中,我們将讨論服務間的通信問題。
===============================================
譯者介紹
陳傑,北京理工大學計算機學院在讀博士,研究方向是自然語言處理在企業網絡信譽評價方面的應用,平時也樂于去實作一些突發的想法。在疲于配置系統環境時發現了Docker,跟大家一起學習、使用和研究Docker。
原文釋出時間為:2015-07-01
本文作者:Sonyfe25cp
本文來自雲栖社群合作夥伴DockerOne,了解相關資訊可以關注DockerOne。
原文标題:微服務實戰(二):使用API Gateway