不會吧!還有人不懂微服務網關:Zuul 的動態路由嗎?我不理解

Zuul 的動態路由

啓動時 Zuul 會讀取靜態配置文件加載路由信息,將 URL Path 與路由映射關係建立好,提前加載到內存。在很多場景下,我們需要在不停止 Zuul 進程的前提下,完成路由映射規則的重新建立,這時候我們就需要動態路由(Dynamic Routing)功能,有兩種實現動態路由的方式。

方式一:通過 Spring Boot Acturator 開啓 Zuul 的 Endpoint 功能,它支持 Refresh 動態刷新配置文件,這種方式的好處是 Zuul 無須做任何修改,也不需要維護路由映射規則,缺點是沒有可視化界面,維護起來比較煩瑣。

方式二:覆寫 RouteLocator 的 ListgetRoutes()方法,通過事件刷新機制,從數據庫中讀取路由配置規則。這是常用的 Zuul 動態路由解決方案,它可以輕鬆地實現可視化管理,減少引入新的 Spring Cloud 組件的依賴綁定。Sia-Gateway(GitHub 已開源項目)使用了基於 MySQL DB 的動態路由機制。如下圖所示是 Zuul 動態路由架構圖。

Zuul 的動態路由思路及解決方案如下。

首先,Admin 作爲前端管理界面將用戶對路由的添加、修改、刪除等操作通過 RouteService 存儲到 DB 中。DB 中的存儲結構如下圖所示。

字段映射關係如下。

● id:標識路由的唯一 ID,唯一主鍵,可以根據路由 ID 查找路由。

● ZuulGroupName:網關集羣組名,標識這個新建的路由歸屬在哪個網關集羣下面。

● apName:應用名稱,標識路由的別名。

● path :匹 配 路 徑 , 新 建 路 由 的 路 徑 匹 配 Patten ( 例如 / foo/),所有發到 / foo/ 路徑下的請求都會轉發到這個路由下面。

● strategy:後端服務策略,後端路由有以下三種策略(只能選其中一種策略)。

○ SERVICEID 策略:針對連接到 Eureka 上的應用,根據配置的 ServiceID,網關會動態匹配一個後端服務。

○ SERVICEURL 策略:針對非 Eureka 上的應用根據配置的 URL 映射到匹配的 URL 後端服務上。

○ LISTOFSERVICE 策略:針對非 Eureka 上的應用,可以選擇多個 IP:PORT(通過逗號分隔)實現路由負載,默認使用 RoundRobin 方式實現負載均衡。

例如 “192.168.1.3:8070,192.168.1.2:8090”。

● SERVICEID:匹配一個新建路由的後端服務唯一標識。

● url:後端服務 URL,匹配一個新建路由的後端服務 URL 物理地址。

● stripPrefix:前綴是否生效,標識這個路由在轉發時是否需要刪除前綴設置。

○ 當 stripPrefix=true 時,主要的路由映射關係如下:

http://127.0.0.1:8181/api/user/list-

http://192.168.1.100:8080/user/list

○ 當 stripPrefix=false 時,主要的路由映射關係如下:

http://127.0.0.1:8181/api/user/list-

http://192.168.1.100:8080/api/user/list).

其次,Admin 對 Route 的狀態管理類似狀態機,網關節點的路由狀態變更通過事件觸發機制實現,以達到路由狀態的一致性。如下圖所示是路由(Route)狀態在 Admin 上的狀態流轉圖。

當 Admin 在修改 Route 狀態時,它需要首先進行 Route 下線,當 Route 處於發佈上線狀態時,執行發佈路由操作會調用 publishRoute 操作,publishRoute 會調用 Gateway 的對外刷新接口,Gateway 會從 Admin 同步最新的路由信息,並將 Route 設置爲發佈狀態。

網關節點的路由管理機制主要由兩部分組成,一部分通過自定義 RouteLocator 從 Admin 同步最新的路由狀態,Admin 會訪問數據庫,並返回給網關節點最新的路由狀態信息,另一部分就是路由緩存狀態管理,即同步更新。下面是代碼實現。

● 說明 1#:CustomizeRouteLocator 是自定義路由加載的核心處理 類 , 該 類 繼 承 了 SimpleRouteLocator , 並 實 現 了 RefreshableRouteLocator 接口。該類的主要功能是覆蓋簡單路由定位器的具體實現類,完成具體路由的加載策略及 Zuul 的內部事件刷新機制。

● 說明 2#:refresh 方法是 RefreshableRouteLocator 刷新事件的 回 調 方 法 , 該 回 調 方 法 在 ZuulHandlerMapping 執 行 setDirty 方法時被觸發。ZuulHandlerMapping 的代碼如下:

ZuulRefreshListener 在 @
ZuulServerAutoConfiguration 自動化配置類中被初始化,setDirty(true)將觸發配置信息的重新加載並觸發 refresh 方法,代碼如下:

● 說明 3#:locateRoutes 方法是 SimpleRouteLocator 的回調方法 , 下 面 是 SimpleRouteLocator 的 具 體 實 現 , 可 以 看 到 SimpleRouteLocator 在 doRefresh 事件中回調了 locateRoutes 方法。

● 說明 4#:這部分代碼是自定義路由加載的核心策略,我們設置了一個布爾型的原子變量:refreshCalled,當這個變量設置爲 true 時,表示需要自定義 Locator,強制從數據庫中加載最新路由信息。當從數據庫同步路由信息並將其存儲到本地緩存中時,將 refreshCalled 設置爲 false,這樣下次加載路由信息時,從緩存中加載就可以了,不需要從遠端數據庫中加載。這樣做的好處是,可以明顯提升維護本地路由信息的效 率 。RouteLocatorUpdater 的 作 用 就 是 當 Admin 調 用 refreshRoute 方 法 時 , 將 refreshCalled 原 子 變 量 設 置 爲 true,強制從數據庫同步加載路由信息。

最後一步,就是 Admin 從數據庫獲取路由數據信息,即從數據庫中加載網關的路由信息,並返回給網關節點,作爲最新的路由信息。

注意:在網關獲取動態路由信息的過程中,使用 REST 方式通過 Admin 代理獲取路由信息,沒有使用網關節點直接去數據庫查詢路由信息,主要有兩個原因:

● 網關如果直接連接數據庫,就會產生網關與數據庫的強耦合關係,對於所有網關服務來說,都需要引入對 MySQL 數據庫的依賴。

● 網關節點服務如果使用連接數據庫的方式,那麼就需要數據庫的相關配置(用戶名、密碼)等信息,從數據安全的角度考慮,網關作爲雲原生的服務資源,應該儘量少暴露給後端用戶,我們應該通過網關 Admin 服務統一管理數據庫資源。

來源:

https://www.toutiao.com/a7026693467883569675/?log_from=39d3835315158_1636593887389

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/j0bMsI3f2Zlic0E6ZRjeBA