導讀
在構建面向企業項目、多端的內容聚合類在線服務API設計的過程中,由於其定制特點,采用常規的restful開發模式,通常會導致大量雷同API重復開發的窘境,本文介紹一種GraphQL查詢語言+網關編排聯合的實踐,解決大量重復定制的問題。
早期與車廠合作過程中,基於高德已有的數據、引擎能力和一些較為重要的相關CP服務(如停車場、加油站、天氣等),形成的在線服務協作模式是針對客戶需求,采用REST API提供針對每個車廠、每個項目以及每個終端提供不同的API實現,然而數據核心獨立服務實際上就有十余種,然而由於車線業務維護周期長,定制多,2-3年下來,API規模已達幾百個,而且持續發散級增長,這給持續開發和維護帶來不小挑戰。
分解業務開發過程,無非兩類工作,業務需求能力數據的獲取和非業務訴求但是必不可少的如鑒權等通用化能力,當前來看,其實這兩個問題是幾乎所有業務團隊都會遇到的問題,因此解決方案也基本類似,如服務聚合、流程編排、API網關等。
本文簡要介紹下車聯網在線服務改造舊架構的一些實踐。
有關名詞
-
GraphQL:GraphQL既是一種用於API的查詢語言也是一個滿足數據查詢的運行時。GraphQL對API中的數據提供了一套易於理解的完整描述,使得客戶端能夠准確地獲得它需要的數據,而且沒有任何冗余,也讓API更容易地隨着時間推移而演進,還能用於構建強大的開發者工具。
-
DSL:指的是專注於某個應用程序領域的計算機語言。又譯作領域專用語言。不同於普通的跨領域通用計算機語言(GPL),領域特定語言只用在某些特定的領域。 比如用來顯示網頁的HTML,以及Emacs所使用的Emac LISP語言。
-
API網關:API網關是一個服務器,是系統的唯一入口。從面向對象設計的角度看,它與外觀模式類似。API網關封裝了系統內部架構,為每個客戶端提供一個定制的API。它可能還具有其它職責,如身份驗證、監控、負載均衡、緩存、請求分片與管理、靜態響應處理。
存在的問題
車線業務在線服務舊架構如下:

面臨以下問題:
改進
針對上述問題,主要從以下幾個方面思考改進:
-
服務能力原子化:目標是做穩,讓上層通過組合實現業務需求;
-
構建查詢引擎:支持強大的查詢組合能力,實現原子服務能力任意聚合和定制;
-
API網關:對非業務數據能力需求進行抽象提供插件,實現插件編排。
下面分別介紹。
實現穩定、獨立演進的原子能力服務
對已有的服務進行梳理,抽象出不同應該獨立開發、部署演進的核心能力,對於引擎能力沒有什么工作,重點是對於一些歷史對接的外部CP,主要實現以下目標:
-
向上提供穩定接口,向下屏蔽底層復雜性(數據訪問,多源差異);
-
以位置為中心有機整合,構建完備原子化能力集合。
這部分工作主要是解決歷史遺留的一些服務組合不合理,跟隨業務過度定制的問題。
定制代碼開發轉換為定義查詢語句
這里主要目的就是將服務聚合、定制邏輯等原來需要的代碼開發轉換為編寫查詢語言的方式實現,只需要編寫出聲明式的查詢語句即完成服務發布,特性如下:
-
向上提供標准化查詢語言
-
向下實現原子能力組合
-
歸納業務共性,提煉定制模式,提升復用
本文選擇GraphQL作為查詢語言基礎,然而,直接采用GraphQL有這樣兩個主要問題需要解決:
-
數據查詢N+1放大問題,直接采用Fackbook提出的dataloader來解決,原理是批量加緩存;
-
GraphQL規范限制,一些定制難以實現,如:
-
入參定制:如參數關聯,類型轉換等;
-
輸出格式:字段展現形式,如時間、經緯度等;
-
配置表定制:主要是部分業務邏輯需要根據配置表定制,如深度返回字段等;
-
模型連接:原子能力服務盡可能獨立,同時也無法枚舉定義模型關系,但是定制業務需求需要大量關聯透出,減少業務請求降低延時,所以模型自由關聯能力是必要的,由於本方案最終的查詢控制在內部,對外暴露REST API,因此不會關聯自由度造成的難理解性並不是一個問題。
需要通過嵌入簡單的DSL實現:
-
內置和自定義函數功能;
-
模型動態關聯查詢,上下文參數獲取;
-
可以方便擴展自定義函數。
這里嵌入DSL需要控制好度,因為DSL如果過於復雜,那么,使用者或者發布者無法快速寫出查詢的話,對比寫代碼提效就會打折扣,偏離本來的價值,所以基本原則是簡單、可擴展。
業務無關功能通過API網關插件配置化
由於之前每個API的定制開發基本所有功能混合在一起,能復用部分就是鑒權提供裝飾器,常規性的響應格式定制提供一些工具函數,任何需求變更都需要變更代碼,走發布流程,有了上面第一步的改造,這個步驟期望將非業務數據部分的定制功能抽象出處理鏈,每個處理節點提供多實現(包含通用和定制),通過數據庫存儲插件鏈實現編排。
車線業務由於鑒權方式需要根據客戶定制,因此存在多樣性,實現上是通過Web中間件實現多種鑒權插件:
-
HTTP簽名,參考這里:主要面向ToB(車廠后台、合作方)的請求;
-
JWT認證:主要面向車機、手機等終端;
-
API Key。
對於API網關來說,這些鑒權插件並沒有什么不同之處,只是工程要處理一些定制場景,比如對於不同車廠的JWK管理刷新策略,JWT驗證策略等,具體需要根據業務訴求抽象建模,通過插件屬性來實現配置控制。
另外,網關還實現了一些變換器,主要用於將GraphQL的輸出變換為REST API接口透出,這一方面由於一些舊接口要做兼容支持,另外,一些重點客戶的全球化架構背景下自己已經完全定義好了接口式樣,目前主要實現了:
-
入參變換:使用REST API參數填充GraphQL查詢模板;
-
Header變換:主要用於適配不同客戶規范;
-
JSON變換,使用場景如下:
-
可復用標准接口,但是不同客戶的響應結構規范不一致
-
定制非標接口,需要對GraphQL輸出進行轉換
而插件的使用則通過控制台或API實現將插件配置信息存儲於數據庫中進行管理,使用時根據請求特征從DB中提取並緩存起來使用。
改造后的新架構如下:
小結
通過上述改造,將車聯網在線服務開發模式進行了升級,實現API控制台動態發布,大幅提升定制開發效率:
- 提效開發:正交化原子能力編排,通過輕量級定義取代定制化代碼開發:
-
定制化開發占比下降60%;
-
單接口開發從2-3人日→2-3人時。
- 協議兼容:混合REST方案,對外提供標准協議、支持既有適配協議。