Spring Cloud Zuul API 網關服務

API 網關是一個更爲智能的應用服務器,它的定義類似於面向對象設計模式中的 Facade 模式,它的存在就像是整個微服務架構系統的門面一樣,所有的外部客戶端訪問都需要經過它來進行調度和過濾。它除了要實現請求路由負載均衡校驗過濾等功能之外, 還需要更多能力比如與服務治理框架的結合、請求轉發時的熔斷機制服務聚合等一系列高級功能。Spring Cloud 中了提供了基於 Netflix Zuul 實現的 API 網關組件 Spring Cloud Zuul。

對於服務實例的維護間題,Spring Cloud Zuul 通過與 SpringCloud Eureka 進行整合,將自身註冊爲Eureka 服務治理下的應用,同時從 Eureka 中獲得了所有其他微服務的實例信息。這樣的設計非常巧妙地將服務治理體系中維護的實例信息利用起來,使得將維護服務實例的工作交給了服務治理框架自動完成,不再需要人工介入。

對於路由規則的維護問題,Zuul 默認會以服務名作爲 ContextPath 的方式來創建路由映射,大部分情況下,這樣的默認設置已經可以實現大部分的路由需求,除了一些特殊情況(比如兼容一些舊的 URL)還需要做一些特別的配置。

對於類似簽名校驗、登錄校驗在微服務架構中的冗餘問題。理論上來說,這些校驗邏輯在本質上與微服務應用自身的業務並沒有多大的關係,所以它們完全可以獨立成一個單獨的服務存在,只是它們被剝離和獨立出來之後,並不是給各個微服務調用,而是在 API 網關服務上進行統一調用來對微服務接口做前置過濾,以實現對微服務接口的攔截和校驗。

Spring Cloud Zuul 提供了一套過濾器機制,它可以很好地支持這樣的任務。開發者可以通過使用 Zuul 來創建各種校驗過濾器,然後指定哪些規則的請求需要執行校驗邏輯,只有通過校驗的纔會被路由到具體的微服務接口,否者就返回錯誤提示。 通過這樣的改造,各個業務層的微服務應用就不再需要非業務性質的校驗邏輯了,這使得微服務應用可以更專注於業務邏輯的開發,同時微服務的自動化測試也變得更容易實現。

微服務架構雖然可以將開發單元拆分得更爲細緻,有效降低了開發難度,但是它所引出的各種問題如果處理不當會成爲實施過程中的不穩定因素,甚至掩蓋掉原本實施微服務帶來的優勢。所以,在微服務架構的實施方案中,API網關服務的使用幾乎成爲必然的選擇。

API網關對微服務架構的重要性

  • 作爲系統的統一入口,屏蔽了系統內部各個微服務的細節。
  • 與服務治理框架結合,實現自動化的服務實例維護以及負載均衡的路由轉發
  • 實現接口權限校驗與微服務業務邏輯的解耦
  • 通過服務網關中的過濾器,在各生命週期中去校驗請求的內容,將原本在對外服務層做的校驗前移,保證了微服務的無狀態性,同時降低了微服務的測試難度,讓服務本身更集中關注業務邏輯的處理。

請求路由

傳統路由方式

傳統路由的映射方式 API 網關根據請求的 URL 路徑找到最匹配的 path 表達式,直接轉發給該表達式對應的 url 或對應 serviceId 下配置的實例地址,以實現外部請求的路由。

在不依賴服務發現機制的情況下,通過在配置文件中具體指定每個路由表達式與服務實例的映射關係來實現 API 網關對外部請求的路由。

傳統路由的配置方式並不友好,它需要運維人員花費大量的時間來維護各個路由 path 與 url 的關係 。

面向服務的路由

通過面向服務的路由配置方式,不需要再爲各個路由維護微服務應用的具體實例的位置,而是通過簡單的 path 與serviceld(服務名) 的映射組合,使得維護工作變得非常簡單。 這歸功於 Spring Cloud Eureka 的服務發現機制,它使得 API 網關服務可以自動化完成服務實例清單的維護,完美地解決了對路由映射實例的維護問題。

可以直接將 API 網關也看作 Eureka 服務治理下的一個普通微服務應用。它除了會將自己註冊到 Eureka 服務註冊中心上之外,也會從註冊中心獲取所有服務以及它們的實例清單。所以在 Eureka 的幫助下,API 網關服務本身就已經維護了系統中所有 serviceId 與實例地址的映射關係。當有外部請求到達 API 網關的時候,根據請求的 URL 路徑找到最佳匹配的 path 規則,API 網關就可以知道要將該請求路由到哪個具體的 serviceId上去。由於在 API 網關中已經知道 serviceId 對應服務實例的地址清單,只需要通過 Ribbon 的負載均衡策略,直接在這些清單中選擇一個具體的實例進行轉發就能完成路由工作。

服務路由的默認規則

默認情況下,爲 Spring Cloud Zuul 構建的 API 網關服務引入 Spring Cloud Eureka 之後,Zuul 爲 Eureka 的每個服務都自動創建一個默認路由規則,這些默認規則的 path 會使用 serviceId 配置的服務名作爲請求前綴。

路徑匹配

不論是使用傳統路由的配置方式還是服務路由的配置方式,都需要爲每個路由規則定義匹配表達式,也就是 path參數。

當使用通配符的時候,經常會碰到這樣的問題:一個 URL 路徑可能會被多個不同路由的表達式匹配上。Zuul 的路由匹配算法中,在使用路由規則匹配請求路徑的時候是通過線性遍歷的方式,在請求路徑獲取到第一個匹配的路由規則之後就返回並結束匹配過程。 所以當存在多個匹配的路由規則時,匹配結果完全取決於路由規則的保存順序。路由規則通過 LinkedHashMap 保存,也就是說,路由規則的保存是有序的,而內容的加載是通過遍歷配置文件中路由規則依次加入的。由於 properties 的配置內容無法保證有序,所以當出現這種情況的時候,爲了保證 路由的優先順序,需要使用 YAML 文件來配置,以實現有序的路由規則。

:properties 的配置內容爲什麼無法保證有序?因爲 Properties 繼承自 Hashtable,而 Hashtable 是無序的,不保證進出順序。

請求過濾

爲了實現對客戶端請求的安全校驗和權限控制,最簡單和粗暴的方法就是爲每個微服務應用都實現一套用於校驗簽名和鑑別權限的過濾器或攔截器。不過,這樣的做法並不可取,它會增加日後系統的維護難度,因爲同一個系統中的各種校驗邏輯很多情況下都是大致相同或類似的,這樣的實現方式會使得相似的校驗邏輯代碼被分散到了各個微 服務中去,冗餘代碼的出現是我們不希望看到的。

所以比較好的做法是將這些校驗邏輯剝離出去,構建出一個獨立的鑑權服務。在完成了剝離之後,有不少開發者會直接在微服務應用中通過調用鑑權服務來實現校驗,但是這樣的做法僅僅只是解決了鑑權邏輯的分離,並沒有在本質上將這部分不屬於冗餘的邏輯從原有的微服務應用中拆分出,冗餘的攔截器或過濾器依然會存在。

對於這樣的問題,更好的做法是通過前置的網關服務來完成這些非業務性質的校驗。 由於網關服務的加入,外部客戶端訪問系統已經有了統一入口, 既然這些校驗與具體業務無關,那何不在請求到達的時候就完成校驗和過濾,而不是轉發後再過濾而導致更長的請求延遲。同時,通過在網關中完成校驗和過濾,微服務應用端就可以去除各種複雜的過濾器和攔截器了,這使得微服務應用接口的開發和測試複雜度也得到了相應降低。Zuul 允許開發者在 API 網關上通過定義過濾器來實現對請求的攔截與過濾,實現的方法非常簡單,只需繼承 ZuulFilter 抽象類並實現它定義的 4 個抽象函數即可。

Cookie與頭信息

默認情況下 Spring Cloud Zuul 在請求路由時,會過濾掉 HTTP 請求頭信息中的一些敏感信息,防止它們被傳遞到下游的外部服務器。默認的敏感頭信息通過 zuul.sensitiveHeaders 參數定義,包括 CookieSet-CookieAuthorization 三個屬性。所以在開發 Web 項目時常用的 Cookie 在 Spring Cloud Zuul 網關中默認是不會傳遞 的,這就會引發 一個常見的問題:如果要將已經使用了 Spring Security、Shiro 等安全框架構建的 Web 應用通過Spring Cloud Zuul 構建的網關來進行路由時,由於 Cookie 信息無法傳遞,Web應用將無法實現登錄和鑑權。可以通過指定路由的參數配置來解決這個問題。

不推薦通過設置全局參數爲空來覆蓋默認值的方法,雖然可以實現 Cookie 的傳遞,但是破壞了默認設置的用意。在微服務架構的 API 網關之內,對於無狀態的 RESTful API 請求肯定是要遠多於這些 Web 類應用請求的,甚至還有一些架構設計會將 Web 類應用和 App 客戶端一樣都歸爲 API 網關之外的客戶端應用。

Hystrix 和 Ribbon 支持

spring-cloud-starter-zuul 依賴包含了 spring-cloud-starter-hystrix 和 spring-cloud-starter-ribbon 模塊的依賴,所以 Zuul 天生就擁有線程隔離和斷路器的自我保護功能,以及對服務調用的客戶端負載均衡功能。但要注意,當使用 path 與 url 的映射關係來配置路由規則的時候,對於路由轉發的請求不會採用 HystrixCommand 來包裝,所以這類路由請求沒有線程隔離和斷路器的保護,並且也不會有負載均衡的能力。因此在使用 Zuul 的時候儘量使用 path 和 serviceId 的組合來進行配置,這樣不僅可以保證API網關的健壯穩定,也能用到 Ribbon 的客戶端負載均衡功能。

參考:

《Spring Cloud 微服務實戰》翟永超 著

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