閘道器異常怎麼解決
一個稍微複雜的微服務叢集服務一般都會有認證和鑑權的統一要求,而且子系統的實現由於出自不同團隊或者部門,或者基於現實的客觀因素考量,可能各自的技術棧都會不同,比如子系統A是java基於SpringBoot技術棧實現,子系統B是基於Python技術棧實現,子系統C也是基於Java開發但是提供的是Dubbo服務。還有就是系統可能跟外部服務整合,這些都是對一個系統的認證,鑑權,服務間呼叫,負載均衡帶來的挑戰。業界通用的做法是為微服務叢集搭建一套閘道器服務,閘道器的實現有多種方式,比如透過Nginx就可以實現閘道器的功能,還有一些開源的閘道器專案比如Kong,Zuul,Spring Cloud Gateway等等,這裡不對個個專案進行對比。本人呼叫下來Spring Cloud Gateway比較適合更復雜場景的閘道器服務實現,感興趣的朋友可以自行呼叫對比其他閘道器專案。下面就講一下透過Spring Cloud Gateway設計一個閘道器服務
系統架構
點選可放大
閘道器接收客戶端http(s)請求或者後端服務間呼叫請求,在閘道器內部採用鏈式處理,每一個鏈路負責某一塊功能,比如,認證鏈路,黑白名單控制,訪問日誌鏈路,請求轉發鏈路,其中請求轉發需要根據不同的協議分別實現轉發功能。然後統一結果處理和異常處理
應用架構
點選可放大
閘道器服務架構中功能模組如下
動態路由管理
統一認證鑑權
協議轉發
負載均衡
服務發現
使用者日誌
基於以上功能模組需求的整體架構設計如下
邏輯架構
點選可放大
閘道器採用分層設計從上到下依次需要實現的功能塊分佈在檢視層,服務層和持久層
檢視層
:實現閘道器配置管理的使用者互動檢視,包括路由配置和多協議服務配置。 路由配置是指配置路由的轉發規則,基於配置的路由轉發主要服務於http(s)和websocket協議服務的轉發。協議服務配置是指配置非Restful服務的服務介面配置,比如dubbo服務的生產者類,和生產者類方法,或者gRPC服務介面protobuf配置。基於rpc協議的dubbo服務的轉發透過自定filter 實現,並透過泛化呼叫和服務提供方在SDK依賴上解耦
服務層
:服務層提供兩大功能模組。路由配置管理介面實現和動態路由轉發實現。
路由配置管理:提供rest介面負責閘道器路由規則的配置管理,該介面只允許閘道器管理員訪問,透過認證服務進行路由配置介面的認證和鑑權
動態路由:動態路由需要同時支援http(s),websocket,rpc介面的路由轉發,其中http(s) 和websocket服務轉發透過動態路由配置實現。rpc介面服務呼叫透過自定義轉發實現,所有的服務轉發都要經過以下公共filter
Black Wither Lister Filter: 驗證客戶端是否在黑白名單中,黑名單的客戶端會被拒絕訪問,白名單的客戶端會跳過認證和鑑權直接進入轉發
Auth Filter:認證過濾器會驗證客戶端身份,透過呼叫認證服務的介面驗證客戶端身份
Permission Filter:許可權過濾器會驗證客戶端是否有呼叫該介面的許可權,透過呼叫認證服務的介面驗證客戶許可權
Log Filter:日誌過濾器會記錄客戶端訪問記錄
Error Filter:當準發異常時會透過Error Filter統一異常返回
除了異常每個路由都要經歷的filter外,不同協議的轉發還可以定製各自的filter實現轉發,例如rpc協議服務的轉發透過自定義的filter實現dubbo介面的泛化呼叫,http(s) 和 websocket協議的轉發透過自定負載均衡過濾器確定轉發地址
持久層:
閘道器採用MySql持久化閘道器配置資料,路由管理服務介面透過Mybatis 框架整合資料庫操作。同時閘道器採用redis作為分散式快取。當應用啟動時從Redis載入所有的路由配置裝載路由物件(RouterLocator)。當透過路由管理服務介面使路由規則放生變化時,透過redis通知閘道器其他服務節點更新RouterLocator物件。
路由配置管理邏輯
點選可放大
路由配置的更改要及時更新到所有閘道器服務節點,這樣匹配到該路由配置的請求在任意閘道器服務節點都可以進行代理轉發,從而使使閘道器的可用性得到提高。我們可以採用API方式主動通知閘道器服務節點重新整理配置,並且監聽重新整理配置結果,任意節點重新整理失敗將會被記錄下來以便問題追蹤處理
點選可放大
服務發現
閘道器在轉發請求到代理服務之前需要透過負載均衡獲取代理服務節點資訊,負載均衡需要根據從服務發現結果查詢節點資訊。因此閘道器需要啟動守護執行緒每秒主動探知代理服務健康狀態儲存最新的代理服務節點資訊
點選可放大
模型抽象
Spring Cloud Gateway 是基於路由定義來實現定製化請求處理,路由定義(RouteLocator)有一個id,一個目標url,一組斷言和一組過濾器定義,我們可以為不同型別的路由轉發定義不同的RouteLocator,這些RouteLocator 會共享一些通用的過濾器,比如認證,黑白名單,鑑權。除此以外不同的RouteLocator 需要定義不同的斷言和過濾器。以下是對於路由路由,過濾器,斷言的抽象
路由
路由是指閘道器對於請求轉發策略的總體定義,閘道器啟動是會初始化所有定義的路由,閘道器資料模型必須包含以下資料
路由id:路由定義的唯一標識
路由uri:路由規則轉發的目標地址其中不同協議的轉發地址根據協議不同定義格式如下
協議型別
字首
佔位符1
佔位符2
佔位符3
佔位符4
http(s)
http://或者https://
目標服務域名
目標服務埠
目標服務名
目標服務介面地址
websocket
ws://
目標服務域名
目標服務埠
目標服務名
目標服務websocket 地址
rpc
dubbo://
目標服務域名
目標服務dubbo埠
目標服務類名
路由斷言:斷言決定滿足何種情況執行路由規則,每個路由規則必須至少含有一個斷言
過濾器:過濾器是指路由轉發經過的切面行為,每個路由除了執行公共的過濾器之外可定義自己的過濾器
斷言
斷言是指路由規則執行必須滿足的條件,斷言規則必須含有以下資訊
斷言名稱(name): 斷言名稱是指路由執行的何種斷言,斷言名稱使用Spring Cloud Gateway內建的斷言名稱,包含以下類別,多種斷言可以疊加作用在同一路由
斷言名稱
解釋
Path
透過請求地址匹配轉發路徑
Before
指定某一時間點之前允許訪問
After
指定某一時間點之後可以訪問
Between
指定某一段時間允許訪問
Cookie
透過驗證cookie匹配轉發
Header
透過驗證header值匹配轉發
Host
透過匹配Host地址值匹配轉發
Method
透過匹配請求方法匹配轉發
Query
透過請求引數匹配轉發
斷言內容: 斷言內容透過key value鍵值對儲存斷言執行內容
過濾器
過濾器是指路由執行經過的切面行為,Ops-Gateway 定位每個路由必須執行以下過濾器
黑白名單過濾器(BwListFilter):
黑白名單校驗,白名單放行,黑名單返回拒絕訪問
認證過濾器(AuthFilter):
對於請求身份校驗,校驗透過則繼續執行下一過濾器,否則返回認證校驗錯誤
許可權過濾器(PermissionFilter):
對於請求身份對於目標介面的許可權校驗,校驗透過則繼續執行下一過濾器,否則返回認證校驗錯誤
日誌過濾器(LogFilter):
日誌過濾器記錄使用者訪問介面記錄和結果
異常處理過濾器(ErrorFilter):
當請求處理異常時統一處理異常返回
根據以上路由抽象閘道器在執行不同協議的請求轉發時的流程如下:
dubbo服務請求
目標服務是Dubbo服務的請求,閘道器層需要整合zookeeper實現服務發現和負載均衡,請求dubbo服務的rest請求路徑斷言,當請求包含服務名稱和方法時,請求需要路由到對應dubbo服務。閘道器服務只需新增對應路由配置和實現泛化呼叫dubbo服務的過濾器,無需依賴dubbo 服務sdk。dubbu服務轉發使用到的斷言型別有,因此dubbu服務轉發需要實現泛化呼叫過濾器
點選可放大
Http(s)和websocket服務轉發
目標服務http(s)web 服務或者websocket服務,請求經過請求路徑斷言(Path Predicate) 當斷言為真時繼續執行filer鏈,其中負載均衡過濾器決定路由請求到到指定服務地址,其中負載均衡斷言需要自定義採用加權輪詢法實現負載均衡
點選可放大