02.26 NGW,前端新技術賽場:Serverless SSR 技術內幕

騰訊 IVWeb team(負責騰訊互動視頻 NOW 直播、花樣直播等產品) 經驗分享~

▎目錄:

  1. 前言
  2. Serverless 的演進
  3. 雲函數 SCF 的開發
  4. NGW Serverless 同構直出方案

前言

最近 Serverless 又火了,有不少業務上雲實裝了 Serverless 雲函數,取得了不錯的落地效果,業界也在不斷探索 Serverless 更多的落地場景。

那麼對於前端來說,Serverless 意味著什麼?對於 Node 服務來說,哪裡可以落地 Serverless?

答:Serverless 同構直出渲染。

Serverless + SSR = ?

Serverless 雲函數:雲計算發展過程中出現的一種計算資源的抽象,它以雲計算平臺為基礎,為開發者提供業務程序的運行環境,開發者無需關注底層資源分配、擴容部署,代碼執行所必要的全部服務由平臺提供。

SSR 服務端渲染: 指在服務端將 HTML 渲染到前端,早期常用 php jsp 技術來在服務端生成 HTML,近年來 JS 同構化趨勢演進下,逐步出現了在服務端上運行前端 JS 代碼進行渲染的方案,如 React、Vue 等主流框架的同構渲染。

若能將 Serverless 技術落地到 SSR 場景,將會有如下優點:

  1. 雲服務資源理論上無限擴容,前端不必考慮業務量對 SSR 機器性能的影響
  2. 前端同學無需關注 SSR 機器的運維、申請、擴容,減少部署運維成本,提高開發效率

目前騰訊 NOW 直播 IVWEB 團隊正逐步將 SSR 業務遷移到騰訊云云函數平臺上,精簡部署運維成本。

Serverless 的演進

阿 J 是一個前端開發仔,某天產品跟他說頁面白屏加載接口的時間太長了,體驗差,這對於優秀的前端開發仔的他並不是難事,他有 99 種讓頁面加載變快的辦法。

因此他立馬將利用團隊直出框架,花了半天時間將頁面接入了直出,接下來要將直出服務部署到現網,這時他犯難了:

  1. 部署直出服務需要申請機器,申請多少臺,申請幾核的?
  2. 這個業務量怎麼樣,有沒有高併發場景,機器有沒有擴容機制?
  3. Nginx 配置怎麼改才能接入直出,直出失敗的話又要怎麼接入兜底的靜態頁面?

一頭霧水之時,他看見騰訊雲的同事 maxlong 關於 Serverless 架構演進的 PPT….

從 IaaS 到 FaaS

在介紹雲函數 SCF 之前,我們先來 diff 一下傳統 IaaS 業務架構和雲函數 FaaS 業務架構:

NGW,前端新技術賽場:Serverless SSR 技術內幕

基於虛擬機的業務架構 (IaaS)

而云函數架構是這樣的:

NGW,前端新技術賽場:Serverless SSR 技術內幕

基於雲函數的業務架構 (FaaS)

阿 J 對比了兩者架構之後發現,在基於雲函數的業務架構下,開發者無需再關注業務基礎層的相關配置,可以集中精力處理業務邏輯的開發,基礎層由平臺負責維護迭代,只要將我們的直出服務部署上雲就可以解決部署直出業務中的運維痛點了。

FaaS + BaaS 下的 Serverless

FaaS 的出現使得服務上雲變得容易起來,但是 FaaS 並沒有解決「公共基礎服務」的問題,而所謂公共基礎服務,就是形如對象存儲、KV存儲、消息推送這樣的基礎服務,這個問題最終落到了雲服務提供商這裡。

因此市面上的雲服務無一例外的都提供了上面的「公共基礎服務」,這樣的服務模式叫做 BaaS(Backend as a Service)。

Serverless 直譯過來叫無服務器,這裡並不是說不需要服務器,而是說開發者不需要關注服務器,這部分由平臺維護提供,開發者僅需關注業務邏輯的開發即可。

NGW,前端新技術賽場:Serverless SSR 技術內幕

Serverless 架構下的 App

在這樣的一種架構下,開發者無須關注支撐應用服務運行的底層資源,以「函數」的形式承載業務邏輯,以「BaaS 服務」的形式支撐公共服務。

NGW,前端新技術賽場:Serverless SSR 技術內幕

公有云基礎設施上的 Serverless 演進

考慮到直出服務的特性,阿 J 認為直出業務十分適合上 Serverless,因此他立馬開始了直出上雲的預研,做 Serveless SSR 服務,免去運維部署煩惱,減少直出接入成本!

SCF 雲函數開發

阿 J 認真研究了騰訊云云函數(Serverless Cloud Function,SCF),發現它可以將我們的業務拆成更細的粒度「函數」,而函數的執行環境開發者不需要關注,由平臺負責,以下是阿 J 對雲函數執行的理解。

雲函數執行過程

雲平臺在執行這些「雲函數」的過程其實就是在對外提供服務,通常情況下,Serverless 函數會用於「響應 HTTP 請求」,即通過 HTTP 訪問事件來觸發雲函數的執行,如下圖所示:

NGW,前端新技術賽場:Serverless SSR 技術內幕

雲函數用戶請求鏈路

而「函數的執行」不外乎:入參、上下文、返回值、副作用四個要素,如圖所示:

NGW,前端新技術賽場:Serverless SSR 技術內幕

函數執行的四個要素

四要素:

  1. 「入參」: 雲函數的入參即 HTTP 請求中的請求頭、請求體
  2. 「上下文」: 包含此次函數請求的 id、函數執行的環境變量等等
  3. 「副作用」: 雲函數執行可能調用外部服務,如數據庫、對象存儲、數據監控
  4. 「返回值」: 即 HTTP 響應如 {retcode:0,msg:"ok"}

阿 J 還了解到根據一定配置部署完雲函數之後,雲平臺會給你一個 URL,通過訪問這個 URL 就可以「觸發」對應雲函數的執行,得到結果。

NGW Serverless 同構直出方案

正當阿 J 著手進行 Serverless 直出開發的時候,他猛然發現,Serverless 環境下跟原有的直出環境有較大出入,原有的直出環境是這樣的:

  1. 原方案直出是使用 TSW 執行 Koa App 的方式進行直出的,這意味著原方案需要監聽端口而不是作為函數來運行,這個要怎麼處理?
  2. 老業務能不能做到無縫遷移到雲函數? 能不能做到新直出方案兼容老直出方案?
  3. 雲函數怎麼做到工程化打包發佈,接入到團隊現有的 CI 流程中?
  4. 原方案可以做本地調試,而云函數直出怎麼做本地調試?
  5. 雲函數發佈後,會得到一個 URL,那麼這個 URL 要怎麼接入我們的業務域名下?

工程化打包

除去前端 webpack 打包之外,對於 Serverless 雲函數平臺,我們還得在原來的打包產物基礎上再做一些操作,其核心在於「打包為 zip 上傳到雲函數」,如下圖所示:

NGW,前端新技術賽場:Serverless SSR 技術內幕

雲函數打包圖示

從圖示中可以看到,打包部署的流程由「CLI 工具」承擔,原因是為了提供命令式的部署原語,方便 CI 接入。

Serverless 下的同構環境

阿 J 考慮到原先業務的直出方案採用 TSW 來做,但是在 Serverless 下,我們不能把 TSW 搬進雲函數里執行,而是抽取了其中我們需要的組件出來,如 ajax 發送請求、監控上報、日誌 logger 等常用組件,因為:

  • 方便老業務無縫遷移到雲函數直出,解決直出業務的運維痛點
  • TSW 很大,壓縮後近 20 MB,解壓出來大很多,不利於雲函數的性能

除此之外,還要自己去實現 window.REQUEST plug 類似這樣的 TSW 全局注入的對象,因為舊有方案也依賴這些全局對象。

「流式」和「塊式」

原來的方案需要 Koa 監聽本地端口才能提供服務,而云函數的出入參是塊式的,Koa 的出入參是流式的,因此這裡需要處理一下雲函數的入參。阿 J 的做法是根據雲函數入參來動態構造 http 的 IncomingMessage 和 ServerResponse 的實例,然後透傳給 app.callback() 進行直出渲染,最後從 ServerResponse 裡取得渲染結果構造為雲函數返回值返回。

NGW 作網關轉發

阿 J 考慮到業務的可用性以及之前鏈路接入的痛苦,決定接入 NGW(Node Gateway):

NGW,前端新技術賽場:Serverless SSR 技術內幕

NGW 下的 Serverless 直出鏈路

通過 NGW 可以做到:

  1. 實現兜底邏輯: 雲函數可能會 crash,這時候走靜態頁面接入機
  2. 灰度邏輯: 直出上現網的過程中可以通過 NGW 的配置進行部分灰度測試
  3. 鏈路日誌收歸: 長期以來,前端不好查具體的鏈路信息,現在有了 NGW 一切皆有可能

雲函數本地調試

雲函數的無狀態模型使得其非常易於進行本地調試,我們只需要在本地構造函數的入參、上下文即可直接進行直出調試了,阿 J 在實際實現中是通過本地起一個 Koa 服務監聽端口,利用這個端口的請求來構造入參、上下文,最後傳入函數執行結果,返回到前端顯示。

同構直出過程

在最後,阿 J 完成了 Serverless 直出方案,其直出過程如下圖所示:

NGW,前端新技術賽場:Serverless SSR 技術內幕

新方案下的同構直出三步

  • 「Init」: 初始化雲函數環境、接受並處理雲函數的入參
  • 「Koa」: React 同構業務邏輯以 Koa App 的形式體現
  • 「Clear」: 清理雲函數環境、處理 Koa Response 返回直出結果

特別需要提出的一點是,其中的 Koa 其實就是原方案的打包結果,新方案在此基礎上作了一些環境遷移、重寫,使其可以在雲函數環境下執行渲染。

雲函數的性能瓶頸和優化

阿 J 在完成了新直出方案之後馬上進行了壓測,發現隨著壓測壓力的增加,收包率會出現斷崖式下跌,而且還發現部分函數執行耗費時間非常長,聯繫了雲函數的同事看了下發現是「冷啟動問題」,那什麼是冷啟動?

從雲函數的架構中可以看到,雲函數觸發後並不是馬上執行,它需要一個環境初始化的過程,這種啟動叫做冷啟動;還有種情況是,這次請求的函數執行之後馬上接到下一次請求,這時候就不用重新初始化雲函數環境,而是直接啟動,這種稱謂熱啟動。

NGW,前端新技術賽場:Serverless SSR 技術內幕

壓測雲函數 執行時間分佈圖


NGW,前端新技術賽場:Serverless SSR 技術內幕

收包率優化前後(右邊為優化後)

冷啟動問題在壓力低的情況下不明顯,但是在高併發的情況下就會額外影響回包了,這裡SCF 的同事進行了優化:提高最小實例數,減少冷啟動,最小實例越多就越能扛住瞬時併發,優化效果如上圖右邊所示。

此外我們還發現了內存的問題,這裡聯繫了 SCF 的同事進行了 Node 內存模型的相關優化,優化後,已基本不存在 4xx 的問題。

(業務中的內存使用也可以進行優化,要避免 JS 內存洩漏)

NGW,前端新技術賽場:Serverless SSR 技術內幕

內存超限導致 4xx 問題,壓測壓力越大越多這種錯誤


NGW,前端新技術賽場:Serverless SSR 技術內幕

內存模型優化後的表現

到這一步,阿 J 終於初步完成了 Serverless 直出方案設計開發,並開始逐步在業務中使用推廣。

現狀和下一步計劃

NGW,前端新技術賽場:Serverless SSR 技術內幕

目前 NGW + Serverless SSR 已經應用到 NOW 直播、手 Q 附近、瀏覽器直播和手 Q 群送禮等多個項目中,實際業務開發中,Node 業務的部署和運維工作量降低了 80% 以上。

阿 J 下一步的計劃:

  1. 完善的雲函數版本管理;
  2. 配合 webpack 進一步優化本地直出調試體驗;
  3. 配合騰訊雲同事進一步優化雲函數性能;
  4. 完善 React Chunked 流式渲染方案,進一步提升首屏加載速度;
  5. 完善 Node 服務雲函數,計劃做前端 BFF 方案;
  6. 完善直出和鏈路日誌收歸,增強服務監控能力。


分享到:


相關文章: