微服務網關——設計篇

微服務網關——設計篇

在《微服務網關——需求篇》中,我們討論了微服務網關的需求,本文將對微服務網關進行設計。考慮到實際情況的差異,這裏實際給出的是設計選項,最終設計基於實際場景來確定。

網關功能性設計

路由

一般情況下,服務對外提供的是 RESTful 接口,所以一般路由模塊根據請求的 host, url 等規則轉發到指定的服務。

考慮到路由規則需要頻繁的修改發佈,爲了發佈的便利性,考慮針對規則實現熱發佈。有幾種實現方式:

基於數據庫

即將路由規則配置到數據庫中,當網關收到請求後,從數據庫中查詢規則進行規則匹配。根據匹配到的規則進行路由。

考慮到性能,可以緩存規則,例如緩存到 redis 中。當修改配置後,需要將修改的數據刷到緩存中。

此方式需要實現數據庫與緩存的同步邏輯,提供操作界面,需要一定的開發量。

基於配置文件

即將路由規則配置到配置文件中,網關啓動時直接加載即可。普通的配置文件方式無法動態處理配置,每次修改後都需要啓動網關,比較麻煩。對於微服務架構來說,一般會有配置服務器,可以基於配置服務器來實現配置的實時生效。

相對於前一種方法,可以基於微服務基礎設施來實現,降低了一定的開發量。

負載均衡

一般負載均衡算法有:

對於微服務場景來說,優先選擇源地址 hash:

聚合服務

聚合服務有兩種方案:

考慮到 GraphQL 的學習成本,以及聚合服務的量不是很多,優先考慮在網關中直接進行編碼的方式。

認證授權

目前大部分系統採用的都是基於 RBAC 的認證授權。RBAC 模型是目前主流權限控制的理論基礎。

RBAC(Role-Based Access Control)即:基於角色的權限控制。通過角色關聯用戶,用戶關聯權限的方式間接賦予用戶權限。如下圖:

RBAC 模型可分爲:RBAC0、RBAC1、RBAC2、RBAC3 四種。其中 RBAC0 是基礎,也是最簡單的,相當於底層邏輯,RBAC1、RBAC2、RBAC3 都是以 RBAC0 爲基礎的升級。具體內容請自行 Google。

考慮互聯網項目對用戶角色的區分沒有特別的嚴格(相對後臺管理系統),RBAC0 模型就可以滿足常規的權限管理系統的需求,所以選擇基於 RBAC0 來實現認證與鑑權。

對於 Java 來說,主流的認證與鑑權框架是 SpringSecurity 和 Shiro,考慮集成的便利性,選擇 SpringSecurity 作爲認證鑑權框架。

過載保護

流量控制

一般的流量控制模式有:

對於微服務場景來說,控制速率是比較合適的流量控制方案。通常情況下,使用令牌桶算法來實現訪問速率的控制,常用的令牌桶算法有兩種:

流量控制算法在確定後也是基本不需要變化的,所以對於熱部署的需求不是必要的。

另外流量控制可以前置,放到接入層來處理,一般的網絡接入服務,如 nginx 是支持流量控制的。如果前期對流量控制沒有太多的定製化需求,可以考慮基於 nginx 來進行處理。

熔斷

服務熔斷的實現思路:

考慮到有較成熟的開源項目,推薦直接使用開源項目來處理。

服務升降級

一種服務升降級的方案可以基於阻塞隊列來實現:

考慮到有較成熟的開源項目,推薦直接使用開源項目來處理。

緩存

考慮到網關是集羣化部署,所以優先使用集中式緩存方式,即網關中所有需要緩存的數據都集中進行緩存。使用常用的分佈式緩存中間件即可,例如 redis。

基於緩存的網關工作步驟:

此處需要注意緩存常見問題:緩存雪崩、緩存擊穿、緩存穿透,需要針對性的做好處理。

服務重試

對於服務重試至少需要提供兩個功能:

對於配置來說,需要配置請求的超時時間、單次請求的超時時間、重試次數,注意單次請求的超時時間 * 重試次數要小於請求的超時時間,否則會影響服務重試邏輯。同時,也需要考慮配置的動態生效,以保障網關的穩定性。

對於執行來說,根據配置的次數來進行處理即可。

邏輯實現並不複雜,不過考慮到有較成熟的開源項目,推薦直接使用開源項目來處理。

日誌

應用日誌記錄遵循項目日誌規範。對於訪問日誌來說,前期可以考慮在接入層實現,例如通過 nginx 的訪問日誌來實現對訪問請求的記錄。待後期有特定需求後再進行定製化。

管理

對於管理功能,由於是非核心需求,前期可以暫不考慮。

網關非功能性設計

高性能

傳統的基於線程的併發模型(Thread-based concurrency),爲每一個請求分配一個線程或進程。這種模型編程簡單,可以將處理一個完整請求的代碼編寫在一個代碼路徑中。這種模型的弊端是,隨着線程 (進程) 數的上升,操作系統在這些線程 (進程) 之間的頻繁切換,將急劇降低系統的性能。

網關作爲整個系統的入口,需要處理大量的請求,故基於線程的併發模型並不適用。需要使用 Reactor 模型來進行處理。

關於 Reactor 模型請參考《EDA 風格與 Reactor 模式

目前常用的 IO 框架 Netty 可通過配置實現上述 Reactor 模型,如自行開發網關,可基於 Netty 進行開發。

高可用設計

高可用包含了前面所說的流量控制、熔斷和服務升降級。除了這些功能外,還需要提供服務的優雅上下線功能以及自身的優雅下線功能。

對於使用 Java 開發的項目來說,由於 JVM 的特性,一般需要一個預熱的過程,即服務啓動後,需要訪問一段時間後,服務纔會達到最佳狀態。如果服務剛啓動就接收高強度的請求,可能會導致響應時間過長、服務負載過高的問題,嚴重時可能導致服務被瞬間壓垮。爲了避免這種情況,網關可以考慮支持 Slow Start 特性。即經過一段時間,逐漸把請求壓力增加到預設的值。

另外,當一個服務下線時,不能直接關閉服務,需要先關閉該服務的對外接口,當該服務處理完所有正在處理的請求並返回後,方可關閉服務。

對於網關自身也類似,當網關需要關閉時,不是直接結束網關進程,而是先關閉監聽套接字,但是繼續爲當前連接的客戶提供服務,當所有客戶端的服務都完成後,再把進程關閉。

擴展性

網關對請求的處理,可以分爲:

對於此類請求的擴展,主要是基於過濾器 / 攔截器來實現。

一般攔截器可以分爲兩大類:

一般來說,先執行全局攔截器,再執行爲了業務邏輯編寫的攔截器。不過,爲了靈活性,網關最好能提供一種機制,可以較容易地調整攔截器的執行順序。最簡單的一種方法,就是給每個攔截器定義一個優先級,網關按優先級順序依次調用各攔截器。

同時,網關也需要能方便的動態配置攔截器,即動態配置攔截器的開啓與關閉、以及配置哪些攔截器針對哪些請求生效。可以通過兩種方式來處理:

伸縮性

網關層爲保證高可用,易於伸縮,快速啓動,需要設計成無狀態的(微服務裏的絕大部分服務都需要設計爲無狀態的)。但是,由於網關需要處理用戶的認證與鑑權,勢必與用戶狀態有關係,此處需要解耦用戶狀態關係。目前一般做法是基於 token 來進行處理:

通過此方式,保證了網關的無狀態,繼而保證網關的快速擴容。

服務監控

對於微服務監控目前市面上有較完善的項目,例如 SkyWalking,Pinpoint。可以基於這些項目快速搭建一個服務監控系統。對於定製化需求,可以進行二次開發。

同時可以基於 ELK 對日誌進行收集分析,方便快速的定位問題。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://www.toutiao.com/i6901247551744557576/