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

1、背景說明

先說明一下背景。php

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

若能將 Serverless 技術落地到 SSR 業務場景,將會有以下優勢webpack

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

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

2、Serverless 的演進

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

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

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

從 IaaS 到 FaaS

在介紹 SCF 雲函數以前,咱們先來 diff 一下 傳統 IaaS 業務架構雲函數 FaaS 業務架構web

基於虛擬機的業務架構

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

而云函數架構是這樣的:ajax

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

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

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

Serverless 架構下的 App

FaaS 的出現使得服務上雲變得容易起來,可是 FaaS 並無解決 「公共基礎服務」 的問題,而所謂公共基礎服務,就是形如對象存儲、KV存儲、消息推送這樣的基礎服務,這個問題最終落到了雲服務提供商這裏,所以市面上的雲服務無一例外的都提供了上面的「公共基礎服務」,這樣的服務模式叫作 BaaS(Backend as a Service)。瀏覽器

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

Serverless 架構下的 App

[ Serverless 架構下的 App ]

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

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

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

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

3、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 就能夠觸發對應雲函數執行,獲得結果。

4、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 已經應用到 NOW 直播、手 Q 附近、瀏覽器直播和手 Q 羣送禮等多個項目中,實際業務開發中,Node 業務的部署和運維工做量下降了 80% 以上。


阿 J 下一步的計劃:

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

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

相關文章
相關標籤/搜索