連接:https://github.com/oopsguy/microservices-from-design-to-deployment-chinese
譯者:Oopsguyhtml
本書的七個章節是關於設計、構建和部署微服務。第一章介紹了微服務架構模式。它闡述使用微服務的優勢與缺點,以及儘管如此,微服務一般是複雜應用的理想選擇。該系列的第二篇文章將探討使用 API 網關構建微服務。java
當您選擇將應用程序構建成爲一組微服務時,您須要決定應用程序客戶端將如何與微服務進行交互。單體應用程序只有一組端點(endpoint),一般使用複製(replicated)結合負載均衡來分配流量。react
然而,在微服務架構中,每一個微服務都暴露一組一般比較細顆粒的端點。在本文中,咱們將研究如何改進客戶端通訊,並提出一個使用 API 網關的方案。nginx
咱們假設您正在爲一個購物應用開發一個原生移動客戶端。您可能須要實現一個產品詳細信息頁面,用於展現給定商品的信息。git
例如,圖 2-1 展現了在 Amazon 的 Android 移動應用中的滾動產品信息時所看的內容。github
即便這是一個智能手機應用,產品詳細信息頁面展現了不少信息。例如,不只有基本的產品信息,如名稱、描述和價格,頁面還展現了:web
在使用單體應用架構的狀況下,移動客戶端經過對應用程序進行單個 REST 調用來檢索此數據,例如:數據庫
GET api.company.com/productdetails/productId
負載均衡器將請求路由到幾個相同應用程序實例中的其中一個。以後,應用程序查詢各個數據庫表並返回響應給客戶端。相比之下,當使用微服務架構時,產品詳細頁面上展現的數據來自多個微服務。如下是一些可能擁有特定商品頁面展現的數據的微服務:編程
咱們須要決定移動客戶端如何訪問這些服務。讓咱們來看看有哪些方式。後端
理論上,客戶端能夠直接向每一個微服務發送請求。每一個微服務都有一個公開的端點:
https://serviceName.api.company.name
該 URL 將映射到用於跨可用實例分發請求的微服務負載均衡器,要檢索特定的產品頁面信息,移動客戶端將向上述的每一個微服務發送請求。
不幸的是,這種方式存在着挑戰與限制。第一個問題是客戶端的需求與每一個微服務暴露的細粒度的 API 不匹配。此示例中,客戶端須要進行七次單獨請求。若是在更加複雜的應用中,它可能須要作更多的工做。例如,Amazon 展現了在產品頁面渲染中如何牽涉到數百個微服務。雖然客戶端能夠經過 LAN 發送許多請求,但在公共互聯網下效率低下,在移動網絡必然是不切實際。
客戶端直接調用微服務的另外一個問題是有些可能使用了不是 web 友好的協議。一個服務可能使用 Thrift 二進制 RPC,而另外一個則可能使用 AMQP 消息協議。這兩個協議不管是對於瀏覽器仍是防火牆都是不友好的,最好是在內部使用。應用程序應該在防火牆以外使用 HTTP 或者 WebSocket 之類的協議。
這種方法的另外一個缺點是它難以重構微服務。隨着時間推移,咱們可能會想改變系統劃分服務。例如,咱們可能會合並兩個服務或者將服務拆分爲兩個或者多個。然而,若是客戶端直接與服務進行通訊,實施這類的重構將變得很是困難。
因爲存在這些問題,不多有客戶端直接與微服務進行通訊。
一般更好的方法是使用 API 網關。一個 API 網關是一個服務器,是系統的單入口點。它相似於面向對象設計模式中的門面(Facade)模式。API 網關封裝了內部系統架構,並針對每一個客戶端提供一個定製的 API。它還可用於認證、監控、負載均衡、緩存和靜態響應處理。
圖 2-3 展現了 API 一般如何整合架構
API 網關負責請求路由、組合和協議轉換。全部的客戶端請求首先經過 API 網關,以後請求被路由到適當的服務。API 網關一般會經過調用多個微服務和聚合結果來處理一個請求。它能夠在 Web 協議(如 HTTP 和 WebSocket)和用於內部的非 Web 友好協議之間進行轉換。
API 還能夠爲每一個客戶端提供一個定製的 API。它一般會爲移動客戶端暴露一個粗粒度的 API。例如,考慮一下產品詳細信息場景。API 網關能夠提供一個端點 /productdetails?productid=xxx
,如圖 2-3 所示,一個使用了 API 網關的微服務。容許移動客戶端經過一個單獨的請求來檢索全部產品詳細信息。API 網關經過調用各類服務(產品信息、推薦、評價等)並組合結果。
API 網關的一個很好的案例是 Netflix API 網關。Netflix 流媒體服務可用於數百種不一樣類型的設備,包括電視機、機頂盒、智能手機、遊戲機和平板電腦等。起初,Netflix 嘗試爲他們的流媒體服務提供一個通用的 API。可是,他們發現因爲設備種類繁多,而且他們各自有着不一樣需求,因此並非能很好地運做。現在,他們使用了 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 組合的另外一個有趣的案例是 Netflix 視頻網格。
使用傳統的異步回調方式來編寫 API 組合代碼會很快使你陷入回調地獄。代碼將會變得雜亂,難以理解,而且容易出錯。一個更好的方式是使用響應式方法以聲明式編寫 API 網關代碼。響應式抽象的例子包括 Scala 的 Future、Java 8 中的 CompletableFuture 和 JavaScript 中的 Promise。還有 Reactive Extensions(也稱爲 Rx 或 ReactiveX),最初由 Microsoft 爲 .NET 平臺開發。Netflix 爲 JVM 建立了 RxJava,專門應用於其 API 網關。還有用於 JavaScript 的 RxJS,它能夠在瀏覽器和 Node.js 中運行。使用響應式方式可以讓您可以編寫出簡單而高效的 API 網關代碼。
一個基於微服務的應用程序是一個分佈式系統,必須使用一個進程間(inter-process)通訊機制。有兩種進程間通訊方案。一是使用基於消息的異步機制。某些實現採用了消息代理,如 JMS 和 AMQP。其餘採用無代理的方式直接與服務通訊,如 Zeromq。
另外一種類型的進程間通訊採用了同步機制,如 HTTP 和 Thrift。系統一般會同時使用異步和同步方式。甚至能夠爲每種方式應用多個實現。所以,API 網關須要支持各類通訊機制。
API 網關須要知道與其通訊的每一個微服務的位置(IP 地址和端口)。傳統應用程序中,您能夠將這些位置硬編碼,但在現代基於雲的微服務應用程序中,找到所需的位置不是一個簡單的問題。
基礎設施服務(好比消息代理)一般都有一個能夠經過系統環境變量來指定的靜態位置。可是,要肯定應用程序服務的位置並非那麼容易。
應用服務能夠動態分配位置。此外,因爲自動擴展與升級,一個服務的整組實例能夠動態變動。所以,API 網關與系統中的任何其餘服務客戶端同樣,須要使用系統的服務發現機制:服務端發現或客戶端發現。 第4章中更詳細地描述了服務發現。如今須要注意的是,若是系統使用客戶端發現,API 網關必須可以查詢服務註冊表,該註冊表是全部微服務實例及其位置的數據庫。
實施 API 網關時必須解決的另外一個問題是局部故障問題。當一個服務調用另外一個響應緩慢或者不可用的服務時,全部分佈式系統都會出現此問題。API 網關不該該無限期地等待下游服務。可是,如何處理故障問題取決於特定的方案和哪些服務發生故障。例如,若是推薦服務在獲取產品詳細信息時沒有響應,API 網關應將其他的產品詳細信息返回給客戶端,由於它們對用戶仍然有用。建議能夠是空的,也能夠用其餘代替,例如硬編碼的十強名單。然而,若是產品信息服務沒有響應,那麼 API 網關應該向客戶端返回錯誤。
若是能夠,API 網關還能夠返回緩存數據。例如,因爲產品價格變化不大,若是價格服務不可用,API 網關能夠返回被緩存的價格數據。數據能夠由 API 網關緩存或存儲在外部緩存中,如 Redis 或者 Memcached。API 網關經過返回默認數據或緩存數據,確保了系統發生故障時最小程度上影響到用戶體驗。
Netflix Hystrix 是用於編寫調用遠程服務代碼的一個很是有用的庫。Hystrix 可使超出指定閾值的調用超時。它實現了斷路器模式,防止客戶端沒必要要地等待無響應的服務。若是服務的錯誤率超過指定閾值,Hystrix 將會跳閘,全部請求將在指定的時間內當即失敗。Hystrix 容許您在請求失敗時定義回退操做,例如從緩存讀取或返回默認值。若是您正在使用 JVM,那麼您必定要考慮使用 Hystrix。若是您是在非 JVM 環境中運行,則應使用同等做用的庫。
對於大多數基於微服務的應用程序來講,實現一個 API 網關是頗有意義的,API 網關充當着系統的單入口點,而且負責請求路由,組合和協議轉換。它爲每一個應用程序客戶端提供了一個自定義 API。API 網關還能夠經過返回緩存或默認數據來掩蓋後端服務故障。在下一章中,咱們將介紹服務間的通訊。
by Floyd Smith
本章討論了 API 網關如何做爲系統的單入口點。它能夠處理諸如負載均衡、緩存、監控和協議轉換等其餘功能 —— 當 NGINX 充當一個反向代理服務器時,能夠做爲系統的單入口點,而且支持全部提到的一個 API 網關具備的附加功能。所以使用 NGINX 做爲 API 網關的主機能夠很好地工做。
將 NGINX 做爲 API 網關並非本書最開始的想法。NGINX Plus 是用於管理和保護基於 HTTP 的 API 流量的領先平臺。您能夠實現本身的 API 網關或使用現有的 API 管理平臺,其中許多使用了 NGINX。
使用 NGINX Plus 做爲 API 網關的理由包括:
NGINX Plus 被普遍用做 NGINX 微服務參考架構中的 API 網關。利用在這裏收集的文章以及 MRA (微服務參考架構)來了解如何在您本身的應用程序中實現這一點。