徹底搞懂服務網關
在分布式架構中,服務網關(Service Gateway)的出現有其必然性。為了幫你理解這種必然性,我們先來討論一下常見的分布式系統組成結構。
一、為什么需要服務網關?
圖中各個客戶端和后臺服務直接交互,我們可以看出三點核心問題。
圖 1 分布式系統組成結構
1. 隔離性
首先,客戶端與服務之間應該確保隔離性,這是架構設計的一條基本原則。
隨著業務需求的變化和時間的演進,各個服務的劃分和實現通常都會做相應的調整和升級。但因為現在服務端的訪問入口是直接暴露給客戶端的,所以如何實現服務端的調整和升級對客戶端透明是一個痛點。
圖 2 服務端功能演進示意圖
2. 訪問粒度
更為重要的是,客戶端與服務端之間應該具備靈活的訪問粒度。
我們知道,每個服務的職責在于提供某一個業務領域的訪問入口,而客戶端一般都需要整合多項業務數據。在現有的分布式架構中,一個客戶端需要和多個服務交互。但是客戶端請求和服務提供的訪問入口在粒度上往往是不一致的,那么不同場景就需要具備對應的粒度關系。
3. 安全性
最后,在客戶端和服務端的訪問過程中,也勢必涉及安全、性能等一系列非功能性需求。
從設計原則上講,這些非功能性需求應該是獨立開發和演進的,但現狀是它們的實現常被夾雜在服務端代碼中,與業務功能混淆,維護性很差。這也是我們在開發分布式系統時的一大痛點。
為了解決上述三個問題,確保客戶端和服務端交互過程的合理設計和實現,我們需要從系統架構的角度來分析。
在軟件設計領域,當我們發現兩個組件之間的關系已經不好把控時,經典的做法就是引入分層思想,也就是在這兩個組件之間加入一個中間層。而在分布式環境下,我們就可以在客戶端和服務端之間架設一層服務網關。
圖 3 服務網關示意圖
在分布式系統中,架構設計上的一個核心要點就是:要確保所有來自客戶端的請求都通過服務網關,再路由轉發到后端服務。這樣,在網關層我們就可以統一攔截和處理請求,實現對訪問粒度的控制、隔離性以及非功能性需求。
那么究竟什么是服務網關?它是如何有效解決這些問題呢?讓我們一起來詳細看一下服務網關提供的解決方案。
二、服務網關提供了什么樣的解決方案?
從概念上講,所謂的網關(Gateway)是在網絡架構中用來實現系統互聯的一種組件。而在分布式架構中,服務網關本質上也是一個后臺服務,為客戶端提供唯一的訪問入口。
1. 路由和解耦
在服務網關中,業務路由支持是它的基礎功能。針對不同的客戶端請求,路由機制能確保將這些請求轉發到最合適的服務進行處理。
因此,在網關層,我們可以統一管理各種服務,為客戶端請求提供更加簡單高效的路由支持。同時,我們也可以制定靈活的路由策略,常見的包括黑白名單、動態規則等。
圖 4 服務網關的路由機制
服務路由功能帶來的作用就是解耦。對于任何系統交互行為而言,解耦都是必須要考慮的設計原則。而從設計模式上講,我們也可以把服務網關看做是外觀(Facade)模式的一種具體表現形式。外觀模式的作用就是把復雜度屏蔽在系統內部,從而降低耦合度。
圖 5 網關模式示意圖
基于服務網關的這種解耦作用,我們就可以解決客戶端和服務端之間的隔離性問題。因為服務網關使得客戶端和服務器端在調用關系和部署環境上實現了解耦,向客戶端隱藏了應用如何被劃分到各個服務的細節。這樣,后臺服務的演進過程顯然就可以不影響到客戶端的訪問過程。
2. 服務適配和 API 優化
服務網關的第二個核心功能是服務適配,即可以根據客戶端請求來動態組合服務端資源,并返回最優的響應結果。
日常開發時,服務網關作為單一入口,通過轉換和適配請求,完成與后臺服務體系的整合。一個典型的場景就是在多客戶端應用中,考慮到不同客戶端頁面展示的差異性,就算是針對同一個場景的業務請求,需要返回的數據可能也會有所不同。
而服務網關可以向每個客戶端提供最優的 API,實現按需獲取數據。例如,對于同樣的用戶信息分頁查詢功能,PC 端和 APP 端的分頁大小就會不一樣,我們需要針對不同客戶端提供最合適的 API。
圖 6 針對客戶端的最優 API 示意圖
另一方面,我們可以想象通過服務網關,聚合后臺服務的調用過程,提供統一面向客戶端的聚合服務效果,這樣就減少了客戶端與服務端的交互次數。
典型的例子就是在電商系統中,原本客戶端的一次請求,可能需要同時訪問用戶服務和訂單服務,才能獲取想要的訂單詳細信息,現在我們可以把所有需要的信息統一,在網關層聚合之后再返回給客戶端,這也是優化 API 的一個場景的維度。
圖 7 使用網關聚合服務調用示意圖
基于服務網關的這種優化 API 的作用,我們就可以解決客戶端與服務之間的訪問粒度問題。服務網關確保了控制訪問粒度的高效性和靈活性。
3. 訪問控制和切面支持
最后,我們需要強調一下服務網關所具備的訪問控制功能,同樣體現在多個方面。
例如,在高并發系統中,通常會采用限流和降級的手段來防止服務不可用。這時候在服務網關上,我們就可以設置對應閾值或規則來限制客戶端請求流轉到后臺服務。
圖 8 網關的安全性和訪問控制功能示意圖
再比如說,對于來自客戶端的任何請求都需要考慮安全性,而服務網關是統一管理安全性的絕佳場所。實現訪問安全性的前提是提供用戶認證,我們可以將用于身份認證的部分功能抽取到網關層。而常見的安全性技術如密鑰交換、報文加解密等功能也都可以在網關中加以實現。
服務網關的訪問控制功能可以說為開發人員提供了強大的切面支持。通過切面,可以把常見的安全性、性能等需求從業務代碼中抽離出來,從而解決在分布式系統中如何有效實現非功能性需求的問題。
三、Zuul 和 Spring Cloud Gateway
介紹完服務網關所提供的解決方案之后,我們接下來討論具體的網關實現工具。
這里,我們選擇 Spring 家族中的 Spring Cloud 展開,這是目前最主流的微服務開發框架。在 Spring Cloud 中,實際上提供了兩款服務網關實現工具,一款是集成 Netflix 中的 Zuul 網關,一款是自研的 Spring Cloud Gateway。
1. Netflix Zuul
正如我們前面分析的,Zuul 網關為開發人員提供了動態路由、訪問監控、安全控制等功能。對于服務網關而言,最重要的功能就是服務路由。在這里,你可以看這個配置示例:
zuul:
prefix: /springsystem
routes:
userservice: /user/**
配置代表了在大型分布式系統中服務網關比較常見的一種應用場景,即在各個服務請求地址上添加一個前綴 prefix 來標識模塊和子系統。同時,我們在“routes”配置段中使用"/user"來為 userservice 這個服務名稱指定請求根地址。這樣,所有通過"/user"地址訪問的請求都將被自動路由到該服務中。
2. Spring Cloud Gateway
Spring Cloud Gateway 是 Spring 官方自己開發的一款服務網關,在技術體系上,Spring Cloud Gateway,基于最新的 Spring 5 和 Spring Boot 2 以及用于響應式編程的 Project Reactor 框架,提供響應式、非阻塞式 IO 模型,所以性能上 Spring Cloud Gateway 顯然要更勝一籌。作為新一代服務網關,我們接下來重點展開 Spring Cloud Gateway。
Spring Cloud Gateway 的基本結構中包含兩個核心組件,一個是過濾器(Filter),一個是謂詞(Predicate)。
圖 9 Spring Cloud Gateway 基本架構圖
過濾器:Spring Cloud Gateway 中的過濾器與傳統 Servlet 中的過濾器是同一個概念,在響應 HTTP 請求之前或之后,用于修改請求本身及對應的響應結果。
謂詞:而所謂謂詞,本質上是一種判斷條件,用于將 HTTP 請求與路由進行匹配。Spring Cloud Gateway 內置了大量的謂詞組件,可以分別對 HTTP 請求的消息頭、請求路徑等常見的路由媒介進行自動匹配以便決定路由結果。
我們來看一下一條基于 Spring Cloud Gateway 的完整路由配置的基本結構,如下所示:
spring:
cloud:
gateway:
routes:
- id: userroute
uri: lb://userservice
predicates:
- Path=/user/**
filters:
- PrefixPath=/springsystem
在上述“routes”配置段中,首先我們使用 id 配置項指定了這條路由信息的編號,這個例子中是“userroute”。而 uri 配置項中的“lb”代表負載均衡 LoadBalance,也就是說在訪問 url 指定的服務名稱時需要集成負載均衡機制。
然后我們使用了謂詞來對請求路徑進行匹配,這里的“Path=/user/**”代表所有以“/user”開頭的請求都將被路由到這條路徑中。
最后我們還定義了一個過濾器,這個過濾器的作用是為訪問路徑添加前綴,這樣當請求“/user/”時,最后轉發到目標服務的路徑將會變為“/springsystem/user/”,而這個路徑會被路由到 userservice 這個服務中。
四、總結
可以說,在當下的分布式系統開發過程中,服務網關已經是一個必備組件。很難想象,客戶端在訪問后臺服務時沒有通過網關進行統一的路由和訪問控制。一旦我們在服務調用過程中添加了一個網關層,那么開發人員就可以集中處理服務路由、服務適配以及常見的安全控制、限流降級等非功能性需求。