李小紅
摘要:芒果TV是以視聽互動為核心,融網絡特色與電視特色于一體,實現“多屏合一”獨播、跨屏、自制的新媒體視聽綜合傳播服務平臺,同時也是湖南廣電旗下唯一互聯網視頻平臺,提供湖南衛(wèi)視電視欄目高清視頻點播服務,并同步推送熱門電視劇、電影、綜藝和音樂視頻等內容,以及部分電視臺網絡同步直播。面對直播一層后端服務等最核心業(yè)務,如何進行技術創(chuàng)新升級值得思考。本文介紹如何在微服務下基于GraphQL構建通用一層服務。
關鍵詞:微服務;GraphQL[1];通用一層
中圖分類號:TP181? ? ? 文獻標識碼:A
文章編號:1009-3044(2022)18-0091-04
開放科學(資源服務)標識碼(OSID):
1 播放一層業(yè)務和技術架構的發(fā)展介紹
播放一層負責客戶端點、直播功能的后端業(yè)務邏輯,是直接面向終端的,所以叫“一層”。
芒果TV從最開始的PcWeb端,逐步發(fā)展為擁有M站、手機、Pad等客戶端,由于早期是按照終端做產品的,也間接決定了播放一層之前的架構。
各個終端發(fā)起HTTP請求到自己對應的播放一層,各端播放一層再請求下游HTTP服務接口獲取數據,進行業(yè)務邏輯處理。
各端播放一層都包含播放的全部業(yè)務,且各端播放業(yè)務大體相似,抽象來說,有取串、播放頁信息、諸多列表和很多配置接口。
此架構的優(yōu)點有:
1)開發(fā)簡潔,功能都在各個終端的播放一層內部,便于軟件設計和開發(fā)規(guī)劃。
2)容易測試,核心業(yè)務沒有復雜的服務調用關系,都是內部調用,方便測試。
3)容易運維,各個終端獨立部署,互相隔離。不存在分布式集群的復雜部署環(huán)境,降低了部署難度。
隨著業(yè)務的發(fā)展,工作模式發(fā)生了變化。由按終端來做產品變?yōu)榻y(tǒng)一做產品和業(yè)務,只是終端的承載方式不同。播放一層老的技術架構漸漸暴露出一些問題。
主要有三個方面問題:
1)由于播放一層包含有復雜的業(yè)務邏輯,在終端、播放一層和服務層職責劃分不清楚的情況下,小需求的修改,需要牽動終端、播放一層和服務層三方;
2)全端的相同需求,相同業(yè)務邏輯需要在各個終端的播放一層實現一遍,產生大量的重復代碼;
3)原生客戶端的版本差異化,是通過增長接口的版本號來實現。隨著版本的快速增長,帶版本號的接口越來越多,難以維護。
2 BFF架構介紹
面對這些問題,我們急需改變。服務化、BFF架構、GraphQL等技術開始實施。接下來介紹播放一層是如何向BFF架構演進的,感受播放一層BFF架構的演進。
要解決播放一層的問題,我們希望:
1)明確定位,明確終端、播放一層和服務層的職責,最主要是搞清楚中間層:播放一層的定位;
2)終端適配,需要一種方便、標準的方式實現多端差異化需求適配;
3)服務化,播放一層合并的過程中抽象出通用業(yè)務可以下沉為服務。
據此,新的架構如圖2所示。
播放一層定位為介于終端和服務層之間的實現終端差異化的系統(tǒng)。
將播放一層的通用業(yè)務獨立為微服務,下沉到服務層。微服務按功能劃分為:起播、取串、播放頁信息、列表等。
將各端播放一層合并為通用一層,合并后如何優(yōu)雅實現多端和多版本的差異化適配成為重中之重,這也是本文的重點。
上述新的架構,其實就是BFF架構(Backend for Frontends),為前端而存在的后端中間層。
傳統(tǒng)的前后端分離應用中,前端直接調用后端服務,后端服務進行業(yè)務邏輯處理。那么引入了 BFF 之后,前端將直接和 BFF 通信,BFF 再和服務層進行 API 通信,所以本質上來說,BFF 更像是一種“中間層”服務。
BFF需要做到實現多端和多版本差異化適配,有下面幾種適配需求。
1)聚合,對于客戶端(特別是移動端)來說,HTTP 請求是很昂貴的,為了減少請求的次數,前端一般會傾向于把有關聯的數據API合并為一個;
2)裁剪,不同屏幕的大小等差異,導致相同接口客戶端需要的響應結果內容大小不同;
3)適配,不同客戶端對后端響應結果名稱要求不同。
3 播放一層使用的GraphQL技術
聚合、裁剪和適配如何實現呢?經調研后,選中了GraphQL,一種為API而生的高性能查詢語言。
GraphQL 作為一種 API 查詢語言,專門用于處理已有服務接口的響應結果,已被Facebook、Netflix、GitHub[2]使用。
例如,一個獲取視頻信息的接口,GraphQL分為服務端描述數據部分,我們在播放一層定義了Video類型數據,有vid,videoName和serialno字段。同時GraphQL會把描述的數據與后端微服務接口做關聯,指定哪個服務的哪個接口返回Video類型數據。
客戶端按需求請求播放一層定義的Video類型數據,例如獲取vid為10000的視頻,且只需要videoName字段。
此時播放一層給客戶端的響應內容就只有視頻名稱信息。
GraphQL并不是一門程序語言或者框架,是一種用于API的查詢語言,它的結構為三層結構。
最上層QuerySchema是客戶端按需請求的接口數據內容,可對服務端描述數據的DataSchema做裁剪和適配等。中間DataSchema是用于服務端描述數據的。最底層的DataFetcher是靜態(tài)數據、DB、第三方接口等的包裝。GraphQL會把DataSchema和DataFetcher做數據上的關聯。
對GraphQL的實現有了初步了解后,接下來介紹GraphQL如何做到:聚合、裁剪和適配,以及GraphQL的高性能和產生的N+1問題解決方案。
3.1 聚合
聚合,多個服務接口數據聚合。
對于客戶端(特別是移動端)來說,HTTP 請求是很昂貴的,所以為了減少請求的次數,前端一般會傾向于把有關聯的數據API合并為一個。
比如Video類型的數據中,客戶端期望返回該視頻的基礎信息同時,還返回播放次數信息。
服務端描述數據Video中增加playCount字段,標識視頻的播放次數。同時給playCount綁定到播放次數服務的接口。
客戶端請求Video數據時,也增加playCount字段,那么服務端響應的Video數據就同時聚合了視頻基礎信息和播放次數信息。
3.2裁剪
裁剪,裁剪掉冗余信息。
客戶端獲取視頻信息時,不需要serialno集數字段,客戶端請求時,去掉serialno集數字段即可,服務端響應的Video類型數據則沒有serialno字段。
3.3適配
適配,自定義響應內容。
客戶端需要接口響應的視頻名稱不是videoName,而是vname,客戶端請求給videoName取別名為vname,服務端響應的Video類型數據中視頻名稱字段則為vname。
3.4高性能
GraphQL引擎不僅靈活,還可以通過指定查詢策略為AsyncExecutionStrategy,實現多個DataFetcher并發(fā)執(zhí)行,提高性能。
比如當QuerySchema獲取視頻信息的同時,還要獲取播放次數和明星列表。
GraphQL引擎在獲取到視頻信息后,會同時發(fā)起播放次數和明星列表的請求。
3.5 N+1問題
雖然GraphQL靈活,但也有天生的缺陷:N+1問題。比如獲取視頻列表的接口,每個視頻都需要返回其的明星列表。
視頻列表下的明星列表:
GraphQL執(zhí)行步驟為:先查詢1次視頻列表,得到多個視頻信息,再遍歷視頻列表,根據videoId查詢明星列表。一共需要發(fā)起N+1次請求,這就是N+1問題。
可以通過FaceBook的DataLoade來解決N+1問題。DataLoader支持通過Cache[3]去除重復請求,同時支持去重、合并后,批量請求。
DataLoader支持通過Cache去除重復請求,同時支持去重、合并后,批量請求。
GraphQL提供了豐富的特性,讓播放一層非常容易就實現了業(yè)務的差異化。例如合集下視頻列表接口,同時有計數信息、是否收藏和明星列表信息。
從業(yè)務上看,在視頻播放頁展示列表時,關心的是計數信息和是否收藏,如圖14左側。
在別的頁面展示列表時,關心的是明星列表數據,如圖14右側。
因為存在不同的使用場景,所以對于同樣的數據卻有著不同的關注點。基于GraphQL的播放一層就是為此而生,輕松即可實現。
GraphQL讓播放一層的版本化不再復雜。假設播放一層視頻列表接口已經上線,提供了isLiked和isCollected的查詢,如圖15左圖所示。
現在需要把接口結構改為中圖所示,需要不影響老版本的API訪問,如果是之前,我們可能會升級API版本。
但在新架構的播放一層中,為了向前兼容,可以使用圖15右圖的結構。
4 播放一層接口配置化
在微服務下基于GraphQL 構建的通用一層是什么樣子的呢?我們實現了配置即可提供新接口給客戶端使用的目標。
播放一層基于Graphql-java開發(fā),整體分為三個部分。
1)QuerySchema部分是接入層,管理QuerySchema配置。支持客戶端傳入QuerySchema,也可以根據客戶端傳入的code或請求path和params通過規(guī)則映射到QuerySchema;
2)DataSchema部分是各個服務返回數據的圖形化組織,用于服務端描述數據;
3)DataFetcher部分是下游服務的抽象層,可配置各個服務的域名、接口地址、請求參數(包括參數驗證)、響應結果等,配套有熔斷、容錯和降級等功能。
播放一層這三個部分,由于主體都是配置文件。故可以做到只需要修改配置,即可在已有微服務的基礎上,開發(fā)出新的接口。
5 結束語
當通用一層算法固定,只有配置變化時,極大地解放了生產力,提高了生產效率。同時與前沿的Serverless[4]、邊緣加速[5]等技術有著友好結合的可能性。
參考文獻:
[1] Matt Asay. How GraphQL turned web development on its head[J]. InfoWorld.com,2020:
[2] 齊晴,曹健,劉妍岑.GitHub中軟件生態(tài)系統(tǒng)的演化[J].計算機研究與發(fā)展,2020,57(3):513-524.
[3] 張?zhí)K豫,江凌云.基于主動緩存的云邊端協同卸載策略[J].計算機工程與設計,2021,42(8):2124-2129.
[4] Hassan H B,Barakat S A,Sarhan Q I.Survey on serverless computing[J].Journal of Cloud Computing,2021,10:39.
[5] 程小蘭.面向邊緣計算的視頻處理加速方法研究[D].杭州:杭州電子科技大學,2020.
【通聯編輯:唐一東】