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

騰訊IVWEB團隊發表於2019-11-15

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

一、背景說明

先說明一下背景。

Serverless 雲函式: 雲端計算髮展過程中出現的一種計算資源的抽象,它以雲端計算平臺為基礎,為開發者提供業務程式的執行環境,開發者無需關注底層資源分配、擴容部署,程式碼執行所必要的全部服務由平臺提供。 SSR 服務端渲染: 指在服務端將 HTML 渲染到前端,早期常用 php jsp 技術來在服務端生成 HTML,近年來 js 同構化趨勢演進下,逐步出現了在服務端上執行前端 js 程式碼進行渲染的方案,如 React、Vue 等主流框架的同構渲染。

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

  • 雲服務資源理論上無限擴容,前端不必考慮業務量對 SSR 機器效能的影響
  • 前端同學無需關注 SSR 機器的運維、申請、擴容

目前 NOW 直播 IVWEB 團隊正逐步將 SSR 業務遷移到騰訊云云函式平臺上,精簡部署運維成本,響應公司自研上雲號召。

二、Serverless 的演進

阿 J 是一個前端開發仔,某天產品跟他說頁面白屏載入介面的時間太長了,體驗差,這對於優秀的前端開發仔的他並不是難事,他有 99 種讓頁面載入變快的辦法,因此他立馬將利用專案中的團隊直出架構半天接入了直出,接下來要將直出服務部署到現網,這時他犯難了:

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

恍惚間,他看見騰訊雲的同事關於 Serverless 架構演進的 ppt ....

從 IaaS 到 FaaS

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

基於虛擬機器的業務架構

[ 基於虛擬機器的業務架構 ]

而云函式架構是這樣的:

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

[ 基於雲函式的業務架構 ]

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

Serverless 架構下的 App

FaaS 的出現使得服務上雲變得容易起來,但是 FaaS 並沒有解決 「公共基礎服務」 的問題,而所謂公共基礎服務,就是形如物件儲存、KV儲存、訊息推送這樣的基礎服務,這個問題最終落到了雲服務提供商這裡,因此市面上的雲服務無一例外的都提供了上面的「公共基礎服務」,這樣的服務模式叫做 BaaS(Backend as a Service)。

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

Serverless 架構下的 App

[ Serverless 架構下的 App ]

使用者無須關注支撐應用服務執行的底層資源,以「函式」的形式承載業務邏輯,以「BaaS 服務」的形式支撐公共服務。

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

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

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

三、SCF 雲函式開發

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

雲函式執行過程

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

雲函式使用者請求鏈路

[ 雲函式使用者請求鏈路 ]

而函式的執行不外乎:入參、上下文、返回值、副作用,如圖所示:

函式執行的四個要素

[ 函式執行的四個要素 ]
  1. 「入參」:雲函式的入參即 HTTP 請求中的請求頭、請求體
  2. 「上下文」:包含此次函式請求的 id、函式執行的環境變數等等
  3. 「副作用」:雲函式執行可能呼叫外部服務,如資料庫、物件儲存、資料監控
  4. 「返回值」:即 http 響應如 { retcode: 0, msg: "success" }

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

四、NGW Serverless 同構直出方案

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

  1. 「服務模式不一樣」: 原方案直出是使用 TSW 執行 Koa App 的方式進行直出的,這意味著原方案需要監聽埠而不是作為函式來執行,這個要怎麼處理?
  2. 「CI 工程化」: 雲函式怎麼做到工程化打包釋出,接入到團隊現有的 CI 流程中?
  3. 「除錯方案」: 原方案可以做本地除錯,而云函式直出怎麼做本地除錯?
  4. 「鏈路接入」: 雲函式釋出後,會得到一個 URL,那麼這個 URL 要怎麼接入我們的業務域名下?
  5. 「老業務遷移」: 老業務能不能做到無縫遷移到雲函式?能不能做到新直出方案相容老直出方案?

工程化打包

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

雲函式打包圖示

[ 雲函式打包圖示 ]

在這裡需要引入一個 CLI 工具來打包 zip 和上傳雲函式,原因是如果需要接入 CI 流程,就要提供命令式的部署來進行 CI 流程。

Serverless 下的同構環境

阿 J 考慮到原先業務的直出方案採用 TSW (github.com/tencent/tsw) 來做,但是在 Serverless 下,我們不能把 TSW 搬進雲函式裡執行,而是抽取了其中我們需要的元件出來,如 tsw ajax http、監控上報、tsw logger 等常用元件,因為:

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

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

「流式」和「塊式」

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

NGW 作閘道器轉發

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

NGW 下的 Serverless 直出鏈路

[ NGW 下的 Serverless 直出鏈路 ]

通過 NGW 可以做到:

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

雲函式本地除錯

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

同構直出過程

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

新方案下的同構直出三步

[ 新方案下的同構直出三步 ]

其中有三個核心步驟:

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

雲函式的效能瓶頸和優化

阿 J 在完成了新直出方案之後馬上進行了壓測,發現隨著壓測壓力的增加,收包率會出現斷崖式下跌,而且還發現部分函式執行耗費時間非常長,聯絡了雲函式的同事看了下發現是「冷啟動問題」,那什麼是冷啟動? 從雲函式的架構中可以看到,雲函式觸發後並不是馬上執行,它需要一個環境初始化的過程,這種啟動叫做冷啟動;還有種情況是,這次請求的函式執行之後馬上接到下一次請求,這時候就不用重新初始化雲函式環境,而是直接啟動,這種稱謂熱啟動。

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

[ 壓測雲函式 執行時間分佈圖 ]

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

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

冷啟動問題在壓力低的情況下不明顯,但是在高併發的情況下就會額外影響回包了,這裡SCF 的同事進行了優化:提高最小例項數,減少冷啟動,最小例項越多就越能扛住瞬時併發。 此外我們還發現了記憶體的問題,這裡聯絡了 SCF 的同事進行了 Node 記憶體模型的相關優化,優化後,已基本不存在 4xx 的問題。

記憶體超限導致 4xx 問題,壓測壓力越大越多這種錯誤

[ 記憶體超限導致 4xx 問題,壓測壓力越大越多這種錯誤 ]

記憶體模型優化後的表現

[ 記憶體模型優化後的表現 ]

到這一步,阿 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. 完善直出和鏈路日誌收歸,增強服務監控能力

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

關注【IVWEB社群】公眾號獲取每週最新文章,通往人生之巔!

相關文章