由淺入深瞭解羚瓏平臺統一接入服務 —— Monet

凹凸實驗室發表於2022-07-14

一、背景介紹

羚瓏作為一款智慧設計平臺,簡單易懂、視覺化操作,同時擁有大量模板與素材為使用者、商家或業務團隊節省了大量作圖時間從而達到降本增效。

隨著使用的使用者越來越多,同時業務也不斷在增長,這也給羚瓏服務端帶來了挑戰。


羚瓏服務端目前架構如圖所示由多個平臺組成,每個平臺都有自己的域名。隨著業務增長每次都是啟動一個平臺來擴充套件功能,這種模式弊端也顯現出來了。

對於後端同學來說,新建一個平臺需要對接登入與許可權;提供的 API 功能沒有集中管理,不清楚正在開發的 API 是否有重複提供;開發的 API 在某些業務場景下還需要自行限流或降級;缺少全域性 API 監控。

對於運維同學來說,要為後端同學開發完成的每個平臺新建域名對映(同時還需要申請證照)。

對於前端同學來說,為了複用某些 API 功能還需要對接多個域名,同時還區分測試與生產環境域名,這就導致前端同學在專案中還需要維護一批域名。

根據以上場景,我們可以總結為,缺少 API 的統一入口與管理(統一域名)、統一鑑權、統一流控、統一監控。

如何解決以上架構痛點?我們需要一個服務承載在業務平臺之上接收前端的請求,轉發到相應的後端平臺上,還可以對每個請求進行使用者認證與許可權校驗,還可以對 API 精準限流與降級,同時對 API 請求響應異常進行監控上報。

這個服務就呼之欲出:API 閘道器,並取名為:Monet。下面我將介紹下這個閘道器中介軟體服務。


二、技術選型

確定了 Monet 需求之後,我們就開始進行技術選型。

基礎框架選擇

牛頓說過,如果說我別人看得更遠些,那是因為我站在了巨人的肩膀上。所以我們需要站在巨人的肩膀才可以看得更遠。那麼 Monet 也一樣,需要選取一款閘道器的框架,並在此基礎之上進行擴充套件。

在技術選型需要從語言體系、社群活躍度、擴充套件性、效能等角度考慮。我們從社群活躍度比較高的選出了兩個分類:非 Java 語言閘道器:Nginx、Kong、Traefik;Java 語言閘道器:Spring Cloud Gateway 與 Spring Cloud Zuul 2。

由於後端採用 Java 的 Spring 生態開發的,所以在程式語言一致性上更加傾向 Java 語言開發的元件。所以在 Spring 生態中有兩款閘道器可供選擇,分別是:Spring Cloud Gateway 與 Spring Cloud Zuul 2

Spring Cloud Gateway 由官方主推閘道器,Zuul 2 由 Netfix 公司開源的閘道器。兩者在實際生產使用效能相比沒有差距,Spring Cloud Gateway 基於 Spring 5.0、Spring Boot 2.0 與 Project Reactor,為服務提供一個簡單有效的 API 閘道器;而 Zuul 1 基於同步 IO 與 Zuul 2 基於 Netty Server 非同步 IO,都是 Spring Cloud 生態中的元件。以下兩者一些區別:

閘道器Spring Cloud GatewaySpring Cloud Zuul 2
易用性簡單易用參考資料較少
可維護性Spring 系列可擴充套件強,易配置可維護性好可維護性差
成熟度Spring 社群成熟,但 Gateway 資源較少開源不久,資料少

兩者相比之下,Spring Cloud Gateway 更具有接入的優勢。所以我們最終選擇了 Spring Cloud Gateway 作為基礎框架


三、落地實現

在前面介紹到我們需要 Monet 來完成統一 API 入口與管理、統一鑑權、統一流控與統一監控。接下來一一介紹實現。

統一 API 入口與管理

統一 API 入口

統一 API 入口比較簡單,我們只需要將一個域名解析到 Monet,Monet 基於 Spring Cloud Gateway 實現,可通過路由配置即可實現將請求轉發到相應服務。這裡講述一下我們實現過程遇到的問題,首先 Spring Cloud Gateway 的路由配置有兩種:專案配置檔案和基於程式碼路由配置

以上兩種都有個弊端,那就是一旦路由配置有變更,都需要將 Monet 服務重啟,在實際生產環境中不太可取。

在查詢了一些資料發現,可以通過 RouteDefinitionRepository 介面實現獲取路由配置資訊,我們可以實現從資料庫中獲取路由配置資訊,當我們變更了路由配置之後,觸發 Spring Cloud Gateway 路由配置過載事件,就可以讓 Monet 獲取到最新的路由配置從而達到動態路由的效果,所以我們可以擴充套件為以下流程:

統一 API 管理

為什麼要做 API 管理呢?API 管理主要為了避免 API 重複建設與 API 安全。

Monet 如何識別請求 URI 是屬於哪個 API 呢?要知道在 Restful API 中 URI 目錄中是帶有引數的,給 Monet 識別是哪個 API 帶來一定難度,但不是不可解。

可以利用 字首樹 資料結構來 API 解析與匹配,字首樹又叫單詞查詢樹,典型應用於統計、排序等等,利用字串的公共字首來減少查詢時間,最大限度地減少不必要的字串比較,從而提高匹配的速度。將 API URI 部分拆分字串後的樹結構示意圖:

<img src="https://storage.360buyimg.com/neos-static-files/4d4b53db-d989-48e9-8de0-ad075c7bb313.png" title="" alt="" width="306">

我們通過實現 Spring Cloud Gateway 的 GlobalFilter 實現 API 解析與監管,通過後端服務匯出 API 資訊匯入到閘道器控制檯(利用 Zookeeper 儲存 API 資訊),API 解析過濾器也是從 Zookeeper 獲取API 資訊並快取,如果找不到匹配 API 只能響應 404,能匹配上 API 的將解析出來的結果放到上下文中,方便後面的過濾器得到 API 資訊進行下一步操作,例如許可權校驗等等;

同時我們也會在閘道器控制檯建立稽核制度,得需要專案負責人稽核後方可將 API 上線。

統一鑑權

統一鑑權也分為兩部分:使用者認證與許可權校驗。

使用者認證

為了讓後端服務無需關注登入流程,使用者登入認證的過程只需要在 Monet 完成,與 API 解析過濾器一樣,使用者認證也是通過 GlobalFilter 實現形成 Monet 的過濾器,使用者認證完了之後每個請求都能讀取到使用者的相關資訊並且放入到上下文中,便於後面的過濾器或者後端服務獲取到。如圖所示:

許可權校驗

為了能夠讓後端服務將許可權集中管理,特地形成了一套許可權體系,並且專門由一個服務負責,並且根據後端服務需求在許可權服務上進行自定義即可形成各個服務許可權,許可權服務就不在此過多講述。由於前面 API 解析已經能夠得到 API 資訊與使用者認證得到的使用者資訊,我們就可以對當前使用者進行許可權校驗了。

統一流控

由於現在的限流與熔斷元件都非常成熟了,我們直接在 Spring Cloud Gateway 所支援的限流與熔斷的元件進行選型,支援限流熔斷元件有:Hystrix 與 Sentinel,兩個元件區別:

功能SentinelHystrix
成熟度社群活躍,文件較全已經停止維護
熔斷降級策略基於響應時間、異常比率、異常數基於異常比率
實時統計實現滑動視窗滑動視窗
動態規則配置支援多種資料來源支援多種資料來源
擴充套件性多個擴充套件點外掛形式
限流基於 QPS,支援基於呼叫關係的限流優先支援
流量整形支援預熱模式、勻速器模式、預熱排隊模式(流量規則可配置)不支援
系統自適應保護支援不支援

根據以上功能區別我們最終選擇 Sentinel ,Sentinel 功能豐富同時我們可將相關限流與熔斷的配置規則放進 Zookeeper 便於我們在閘道器控制檯上進行配置,通過 Sentinel 可以對使用者、IP、或者 API 級別進行限流或者熔斷降級能力。

統一監控

API 的監控也是比較簡單,也是通過實現 GlobalFilter 並且在 API 解析之後,拿到 API 資訊並記錄請求資訊上報,例如:API 請求時間、響應耗時等資料。在此處為了能夠適配各種監控系統,在此處定義了一套監控介面,只需要實現該介面即可實現不同監控系統,例如:內部版本接入京東內部監控系統,對應的就是獨立一個實現;同時可根據監控介面對接另外一套監控平臺,更具有擴充套件性。

以上就是完整的 Monet 架構。

四、總結

我們先通過介紹目前架構的痛點講述專案背景及技術選型,基於 Spring Cloud Gateway 落地實現 Monet 中的 統一入口與 API 管理、統一鑑權、統一流控、統一監控。雖然完成了以上功能,但是其實還有很多需要擴充套件的地方,例如:API 管理的稽核流程、接入非 Java 服務、Access 日誌等等。

相關文章