減少重複開發,GraphQL在低代碼平臺如何落地?

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對比:


    性能

    文檔

    調試

    學習成本

    GraphQL

    性能好,申明式獲取,非常直觀和精準,減少不必要數據網絡傳輸

    代碼即文檔

    前端能快速感知,強類型,避免出錯

    Rest API

    缺乏彈性,大多數情況會獲取額外數據

    使用Swagger

    後端配合排查

表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,進行服務隔離,可以更高程度的保證服務穩定。


也許你還想看
低代碼在愛奇藝鵲橋數據同步平臺的實踐
代碼質量提升之道——代碼覆蓋率原理與移動端工程實踐

 掃一掃下方二維碼,更多精彩內容陪伴你!

本文分享自微信公衆號 - 愛奇藝技術產品團隊(iQIYI-TP)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章