首頁>技術>

2015年,Facebook推出了GraphQL(Graph-Query-Language)查詢語言。到目前為止,IBM、Twitter、Walmart Labs、紐約時報、Coursera等很多公司已經在內部從RESTful轉向GraphQL API

作為一種查詢語言,GraphQL具有以下特點:

(1)無需關心如何更新文件,所有的查詢(query)和變更會自動形成文件(cchema)

(2)無需獲取整個資料集,透過schema與resolver(處理器)之間的對映關係,由對應的resolver去獲取資料,將結果返回給前端,從而可以編寫僅僅返回所請求資料的查詢。

(3)對前端提供統一的訪問點。從不同的API中獲取資料並非易事,GraphQL支援將所有API進行拼接

愛奇藝號技術團隊在實施微服務化的過程中,受到Forrester Research提出的低程式碼開發(Low-Code:即無需編碼或透過少量程式碼就可以快速生成應用程式的開發理念)的啟發,基於GraphQL構建BFF(Backend for Frontends),幫助開發人員用拖拽式操作,直觀地創建出一個供前端呼叫的API,本文將對實施過程中的經驗總結進行敘述。

GraphQL介紹

與 RESTful API 一樣,GraphQL API設計用於處理 HTTP 請求併為這些請求提供響應。REST API 構建在請求方法和端點之間的連線上,而 GraphQL API 被設計為只通過一個端點,始終使用 POST 請求進行查詢,其 URL 通常是xxx.com/graphql。圖1-1為GraphQL部署架構圖,可以看到它處於系統“中間層”

圖1-1

GraphQL 全稱叫 Graph Query Language,官方宣傳語是“為你的 API 量身定製的查詢語言”,用傳統的方式來解釋就是:將你所有後端 API 組成的集合看成一個數據庫,使用者終端傳送一個查詢語句,你的 GraphQL 服務解析這條語句並透過一系列規則從你的“API 資料庫”裡面將查詢的資料結果返回給終端,而 GraphQL 就相當於這個系統的一個查詢語言,像 SQL 之於 MySQL 一樣。GraphQL執行過程如圖1-2所示:

圖1-2

圖1-2是GraphQL 執行的大致流程,第一步去驗證查詢語句是否符合GraphQL的schema規範,確認查詢內容的合法性,第二步生成執行的上下文,關鍵點在第三步和第四步,第三步是獲取查詢語句所需要查詢的欄位,這裡叫 fields,所有需要查詢的欄位可以在查詢語句裡拿到,這就是 GraphQL 如何做到避免返回冗餘資料的。拿到所有需要查詢的欄位後,第四步針對每一個欄位去執行它的 resolver,可以從 resolver 返回的資料裡面拿到欄位對應的資料,最後是格式化結果並返回。

重點是第四步,展開說明一下,如圖1-3、圖1-4所示:

圖1-3

圖1-4

在GraphQL裡面有一個概念叫型別 (type),每一個型別下面對應的是一個或多個欄位(field),每個欄位都會繫結一個處理器(resolver),這個 resolver 的作用就是獲取欄位對應的資料

對應到圖1-4所示,UserInfo這個型別,它有三個欄位:nickName、contractNo、fansNumber。每個欄位都對應一個resolver,resolver 需要被開發者重新定義,否則會報錯。所以UserInfo下的三個欄位nickName、contractNo、fansNumber需要透過實現各自resolver來分別從使用者微服務、合同微服務、粉絲微服務去獲取使用者資訊、合同資訊和粉絲資訊,然後再聚合返回,這樣就達到了使用 GraphQL 進行資料拼接的目的

BFF架構

愛奇藝號在實施微服務化的過程中,加入了BFF的前後端架構,如圖2-1所示:

圖2-1

從圖中可以看出,BFF作為前後端的中間層服務。主要的業務邏輯都封裝在BFF層,前端透過BFF進行訪問,減少微服務之間的相互呼叫。BFF層透過REST API方式提供服務,隨著服務的增多,提供的介面越來越多,這會導致REST API越來越冗餘。對於前端而言,有的API粒度較粗不滿足需求;有的API又粒度太細,不僅增加了響應時間,還會造成流量的浪費。對於後端而言,前端需要的資料往往在不同的地方具有相似性,但卻又不盡相同,比如:針對使用者資訊,有些地方需要使用者簡要的基礎資訊和詳細的影片資訊,而有些地方卻需要使用者詳細的基礎資訊和簡要的影片資訊。這往往需要開發不同的介面去滿足各種定製需求,增加了開發人員的工作量,提升了開發工作的重複度。

GraphQL與Rest API對比:

表2-1

從表2-1中的對比可以看出,GraphQL相對於Rest API方式,效能更好,能有效減少前後端開發溝通成本。但是Facebook的官方只有JS版本實現,查詢方式和Rest API也有所不同(如表2-2所示),對於老專案有一定的遷移、學習成本。

表2-2

接下來,本文將主要探討如何基於graphql-java,做到減少遷移成本的同時,又能提升後端開發人員的效率,避免重複開發。

愛奇藝號API生成平臺實踐

愛奇藝號API生成平臺,是一個低程式碼平臺。由於愛奇藝號的技術棧主要基於Java,所以使用的是GraphQL的 Java實現。基於graphql-java,API生成平臺主要做了以下功能最佳化及增強。

(1)支援Rest API:降低前端接入成本。

(2)動態接入監控:動態生成的API,與其他普通介面一樣支援Prometheus監控,保證監控的靈活性和服務的穩定性。

(3)靈活配置:可以動態生成GraphQL的schema,方便後端接入新服務。

(4)視覺化API管理平臺:API介面提供視覺化操作,方便檢視、新增、修改和重用。

接下來將對以上功能進行詳細介紹:

1.支援Rest API

graphql-java透過Spring的封裝,位於整個架構的閘道器層或BFF層。專案user-info-graphQL依賴graphql-java-spring,支援Rest API請求。平臺的整體架構圖如圖3-1所示:

圖3-1

User-info-graphQL的服務流程圖如圖3-2所示。客戶端透過graphql/字首的Rest API方式請求,後端透過字首與GraphQL Query繫結,從DB獲取對映關係,最終轉換成GraphQL支援的查詢語法。

圖3-2

2.動態接入監控

在user-info-graphQL專案中,原本是透過template url來匹配任意自定義url;導致監控平臺只能顯示template url的請求資訊,如圖3-3所示。這個問題可以透過重寫spring-boot-actuator中獲取tags的方法,將真實的url請求資訊暴露到Spring boot的/actuator/prometheus端點這個方法來解決,如圖3-4所示。

圖3-3

圖3-4

透過暴露的監控端點接入Prometheus,實現對新生成的API進行實時動態監控,示例效果如圖3-5所示:

圖3-5

3.靈活配置

為了方便後端快速接入新增微服務,達到支援API動態擴充套件目的。專案中透過Velocity定義schema模板,透過Java註解、反射機制動態生成graphqls模板檔案,如圖3-6所示:

圖3-6

圖3-6中的GraphQL schema模板,支援透過使用者UID查詢使用者資訊。使用者資訊是由多個微服務聚合而成,採用非同步呼叫多個微服務並行獲取資料。基於此模板,使用者只需要實現SPI定義好的介面,就能實現對新增微服務的支援。4.視覺化API管理平臺 透過API生成管理平臺,開發人員可以實現API介面的視覺化配置、生成、動態監控等功能,達到開箱即用的效果,極大提升開發和運維效率

總結

透過GraphQL動態構建BFF服務層API,聚合不同的微服務,相比於Rest API方式,能夠減少後端重複開發,加快響應前端需求。後端開發人員只需要開發維護新增微服務,並透過SPI方式,增加BFF層對新增微服務的支援即可。價 值:透過在愛奇藝號後端微服務引入GraphQL構建BFF服務層,可以達成以下效果:

開發方面的優勢

提升開發效率:後端開發人員職責分工明確,微服務與BFF層獨立開發及維護。新增微服務接入方便,因BFF層對外的API支援動態生成,所以無需更改BFF層的程式碼,只需集中維護微服務。前端可以透過GraphQL的schema檢視介面返回資料,減少前後端溝通成本。形成低程式碼平臺:隨著構建的微服務基礎措施足夠完善,BFF層支援動態生成API介面,極大減輕重複工作量。

執行維護時的優勢

便於監控:新增BFF層API介面,透過支援Prometheus端點監控,無開發成本。支援系統高吞吐量:BFF服務、微服務都是基於docker部署,支援QPS動態擴容,能夠支援高併發。便於維護和擴充套件:基於GraphQL構建的BFF層,API介面動態生成,層次清晰,更易維護、擴充套件。

難 點:

動態擴充套件查詢支援,目前schema的定義都是基於明確欄位的情況下,如果需要支援動態的查詢支援,需要支援動態schema擴充套件和解析。中文文件少,Facebook官方只發布了JS實現,Java實現都是基於開源社群,文件和功能都不是很完善。

未來規劃:

隨著BFF端對API請求的多樣化,需要動態支援新方法擴充套件及監控。目前API與請求的對映關係持久化在MySQL中,需要支援叢集和高效能,後續逐步遷移到ZK或Redis中,並快取到本地。

隨著雲原生和K8s的興起,基於K8s部署的Go服務,更易擴容和維護。基於Java實現的GraphQL,如果遷移到K8s上部署,很難實現快速擴縮容的效果。而graphql-go在github上的star高達7k,可見熱度極高。如果基於Go實現BFF端,API與請求的對映關係可以儲存於K8s的Pod配置檔案中,並且透過一個API部署一類Pod,進行服務隔離,可以更高程度的保證服務穩定。

13
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • HTML5模板:適用於任何專案的基本樣板