作者 | 繁易
這是 Midway Serverless 體系在 8月底位于阿裡雲雲原生微服務大會對外分享的内容文字版,介紹了 Midway Serverless 全新的類 React Hooks 風格的 Serverless 開發方案,點選閱讀原文立即體驗,歡迎閱讀和轉發。
大家好,我是來自淘系技術部 - 前端架構團隊的繁易,今天我要給大家來分享是《Midway Serverless,新一代雲端一體研發架構》。向大家分享我們是在如何在開發過程中,打破雲和端的那堵牆,進而去享受真正的雲端一體應用研發。

我的花名叫繁易,目前就職于阿裡巴巴-淘系技術部-前端架構團隊,主要負責淘系前台業務的 Serverless 落地和前端提效戰役,目前也在負責 Midway Serverless 架構雲端一體場景的架構設計和落地工作。
大綱
本次分享我将會從以下 4 部分出發:
- 阿裡巴巴 Node.js Serverless 建設現狀
- Midway Serverless 介紹
- 新一代雲端一體研發方案
- 未來規劃
在過去的2019年中,阿裡經濟體前端委員會提出了四大技術方向。分别是:
- 搭建服務
- Serverless
- 智能化
- Web IDE
Serverless 與前端
Serverless 首次作為一個技術方向,被列為前端委員會的主要攻關方向。這背後也是有一定原因的。
首先是在阿裡巴巴集團,我們擁有 1600+ Node.js 應用,但應用常年的 CPU 使用率非常低,大部分 CPU 使用率 < 10%,甚至有 < 5% 的應用。
從技術視角來看,Node.js 的維護實際上是有一定難度的,在開發的過程中,我們會遇到非常多前端之前所沒有處理過的問題。例如 Docker、限流、日志、跨語言調用等。而這一系列的難題則會帶來非常高的成本。
恰巧的是,這些傳統應用開發所會面對的一些問題,正好是我們函數開發中的優勢。因為函數可以提高伺服器的使用率,按量付費,也可以減少非常多不必要的運維成本。
而從業務視角來看,前端也提出了一些業務上的訴求。阿裡巴巴是幾年前開始了中台戰略,并希望做到大中台小前台的目标,是以我們前端同學,也希望借中台服務來快速組合為各類業務接口,進而達到快速傳遞的目标。更快的完成業務需求和降低業務試錯成本。
是以我們需要 Serverless 來賦能前端,讓雲原生給前端降本增效。
Serverless 落地成果
經過大約一年的實踐之後,我們也取得了一定的一些成果。
首先,我們在多個 BU 實作了 Serverless 的落地 ,平穩度過了雙促。這些 BU 大家可能也都很熟悉,比如:淘系、新零售、飛豬、ICBU、天貓精靈等。
而在業務增效降本上,Serverless 也有亮眼的表現。
在機效方面,我們傳統業務機器成本降低 ~30%,而中背景業務機器成本更是降低 ~87%,Serverless 幫我們節約了成本的同時,也一定程度上解決了伺服器使用率低下的問題。
在人效方面,使用函數整體人效提升 ~48%。這部分是我們根據使用者使用工具埋點 + 調用時長 + 代碼量測算得出。
最後則是 Serverless 整體架構經過了雙促的驗證,零故障。有力的證明了 Serverless 架構的穩定性。
Midway Serverless 體系介紹
我們在整個 Node FaaS 落地的過程中,都是基于我們 Midway Serverless 架構去開發的。是以在講述雲端一體前,我還會向大家介紹一下整個 Midway Serverless 的體系。
簡介
下面我們以請求調用為例,大家可以看到請求處理的過程中,雲開發平台的 Runtime 會加載 index.js,而 index.js 又會執行我們的 Midway Serverless Framework,最後再由架構去執行使用者代碼,傳回結果。
體系
而在整個 Midway Serverless 的體系裡面。我們一共有以下三個部分:
- 工具鍊
- 架構
- 标準化
首先是工具鍊,我們在本地工具鍊這邊做了非常多的事情。包括本地觸發器的模拟、調試、一體化、多平台的釋出等。
第二部分則是架構,包括資料模拟、環境配置、請求适配、元件拓展、IoC 等。這部分都是希望開發者可以更友善的去開發應用。
最後一個則是标準化。目前雲廠商在 Serverless 标準層面是割裂的,而我們則希望一定程度上的去解決這個問題,比如我們推出的 yml 标準、前端調用标準,運作時标準、一體化标準。這一切都是希望大家在 Serverless 時代能更好的去利用 Serverless 的紅利來加速開發。
這部分我們将會向大家介紹新一代一體化雲端一體研發方案,至于為什麼是新一代,這兒先賣個懸念,後面會提及。
我們遇到的問題
在阿裡巴巴實踐 Serverless 并不是一帆風順的,我們也遇到了許多難題。
首先是上手難度高的難題,因為 Serverless 雖說把運維的成本降低了,但是你在開發一個應用時,需要去接觸後端,相比于傳統的前端開發來說,難度是升高的。
其次是前後端割裂的問題,我們現階段主要在負責純函數的開發。從代碼層面來看,就是前端是一個倉庫,後端是另外一個倉庫,前後端分開開發與釋出。雖然都是一個人在做,但依然會有比較強的一個割裂感。
最後則是研發成本高問題,上面提到前後端割裂的問題,當你前端和後端在不同的倉庫時,意味着你需要分開釋出,并且多次聯調,這部分帶來的研發成本是偏高的。
帶着這些問題,我們經過了大約一年的思考與探索,推出了我們自己的解決方案:雲端一體應用開發模式。
雲端一體在社群的定義
雲端一體這個概念并不是一個新詞,近期在社群也很常見。而在社群的視角上,關于雲端一體主要有以下兩種定義。
架構視角
第一種是架構視角出發的。他們所認定的雲端一體,是雲服務和端側技術能夠結合在一起使用。比如說前端使用 BaaS 服務進行開發,他們把這種開發模式就叫雲端一體。
代碼視角
另外一種是從代碼視角出發,目前後端同倉庫時,我們通過 monorepo 等工具進行開發,也被稱之為雲端一體。
像下圖中展示的就是一種比較經典的研發模式。Server 端與 Web 端分别是一個檔案夾,雙方管理自己的依賴,一同開發與一同釋出,這種也稱之為雲端一體。
但是我們在去年調研方案時,我們覺得這兩種方向,隻是機械的将資源組合在一起,并沒有發揮出 JavaScript 統一前後端的優勢。
Midway Serverless 的雲端一體方案
對此,我們也提出了自己的雲端一體解決方案。新方案的定義為:雲端協同開發、無縫融合。
然後在下圖有我們方案的一個目錄結構。在新方案中,前後端是在同一個倉庫裡的,而且前後端隻需要管理一份依賴。這麼做有以下幾個好處:
- 易于開發:前後端在一個倉庫裡,隻需要管理一份依賴。可以降低開發時的心智負擔
- 易于維護:前後端都在一起的時候,功能是一同開發一同管理的,可以提升項目的可維護性
- 易于部署:前後端都是一個倉庫,在一次釋出中,我們可以同時釋出前後端,降低部署的成本
Midway Serverless 雲端一體特性
我們這次推出的雲端一體方案,主要有以下4個特性:
- 函數式研發(Functional R&D Solutions):函數即接口。我們通過函數來統一前後端的體驗,減少不必要的樣闆代碼,加速應用研發
- 一體化調用(Api not required):從此不再手動調用 Api。在新架構中,你可以直接從服務端導入函數并調用,就像調用普通函數一樣簡單
- Hooks(Using Node.js like React Hooks):通過 Hooks 開發 Node.js 應用。是全新的體驗,也是你熟悉的文法。更為函數式開發帶去了完善的能力支援
- 漸進式開發(Progressive development):簡單和複雜場景通吃。通過對于 IoC 的支援,我們可以複用阿裡 Node.js 複雜應用最佳實踐,支撐企業級應用開發
函數式研發:Functional R&D Solutions
目前雲廠商接口開發模式
在目前的雲廠商提供的 Serverless 服務中,不同雲廠商的接口開發方式是不一樣的。
比如說阿裡雲,騰訊雲、AWS這三個雲平台,他們都有着不同的入參。而不同的入參意味着需要開發者去自行了解各個平台間的差異,學習成本高。
我們在經過思考之後,覺得這種開發模式所帶來的成本太高了,那麼有沒有一種更簡單的方式呢?
用最簡潔的方式開發接口
答案是有。
我們發現,其實使用原生的 JavaScript 函數,就可以實作我們的目标。以下圖為例,左邊的是 Get 接口的開發方式,右邊的是 Post 接口的開發方式。
當函數沒有參數時,則接口的 HTTP Method 為 Get,而當接口需要傳參時,它就是一個 Post 接口,整個開發方式是自然且完全對齊 JavaScript 函數開發體驗的。
像寫 JavaScript 函數一樣寫接口。
函數元資訊
使用 JavaScript 函數,是可以描述函數的資訊的。
JavaScript 函數與接口元資訊的映射關系如下:
- 路徑:檔案名 + 函數名
- HTTP Method:函數是否有參數
- HTTP Request Body:函數參數
通過這種方式,我們使得函數元資訊能轉換為接口的資訊,來進行 HTTP 服務的開發。
一體化調用:Api not required
我們通過函數自身的資訊,來生成接口的資訊,這中間實際上包含了一個轉換的過程。如果要讓開發者手動拼接路徑,調用函數,那無疑是一種倒退。
接下來展示的一體化調用則會向大家展示我們是如何解決這個問題,充分發揮函數的優勢。
重塑接口調用體驗
在過往的開發中,我們要完成接口的請求,總是需要手動去拼接參數并且調用,整個過程顯得繁瑣不堪。
而在雲端一體的開發場景下,我們希望重塑整個接口的調用體驗,真正做到雲端融合,忘記 Api 和 Ajax 調用。
一體化調用:最簡單的接口請求方式
我們選擇使用函數開發接口,是為了實作一體化調用。所謂一體化調用,就是在接口的調用過程中,我們不再手動調用 Ajax 與 Api,而是直接通過 JavaScript import 的方式,導入函數并調用。
調用接口,就和調用普通函數一樣簡單。
Get 接口調用
Post 接口調用
和普通函數一樣寫接口,也和普通函數一樣調接口,從此忘記 Ajax 和 Api 調用。
前後端調用示例
實作原理
一體化調用的實作原理并不複雜,我們基于 Webpack 和 Babel 開發了編譯插件,将前端對于函數的引用轉換成了 HTTP 的請求。
具體的可以看下圖:
Hooks:Using Node.js like React Hooks
為什麼會有 Hooks
在傳統的 Web 應用開發中,我們需要的不僅僅是函數參數,還包括非常多的請求上下文資訊,例如請求的 Header、Method 等。
但在一體化調用中,由于接口也是通過 JavaScript 函數開發,是以無法擷取到請求上下文的資訊,也不能通過參數手動傳入(因為會損害調用體驗,前端也無法傳入上下文參數)
通過 Hooks 擷取請求上下文
我們在借鑒和吸取了 React Hooks 的經驗之後,決定通過 Hooks 去解決擷取請求上下文的難題。
整個 Api 非常簡單:
const ctx = useContext()
通過 useContext 這個 Api 與 Hook 的開發方式,帶來了以下三個好處:
- 解決了在函數中擷取請求上下文的難題
- 無需手動傳入參數,不損害調用體驗
- 遵循 React Hooks Style 的開發方式,雲端一體融合不僅僅是項目目錄結構與接口調用的融合,更是開發心智的融合
下面是一些簡單的示例:
通過 Hooks 的方式,我們可以像寫 React Hooks 一樣去開發 Web 服務。
可複用的 Hooks
在 Hooks 的開發中,我們也支援将複雜或重複的邏輯,提取成單獨的 Hooks 并進行複用,進而減少重複性的勞動。
實作原理與性能問題的解決
在實作 Hooks 文法的支援時,實際上是存在一波三折的。
在社群上,Node.js 官方提供了 Async Hooks 這個子產品,可以用于模拟實作請求上下文的傳遞功能。但該子產品也存在兩個問題:
- 子產品 Api 不穩定
- 性能問題嚴重
其中,第二個問題是我們棄用該方案的直接原因,具體的 Benchmark 可以看下圖:
Async Hooks 所帶來的性能損耗十分驚人
是以,我們嘗試另辟蹊徑,通過在工程上預編譯的方式,來實作 Hooks 的開發與請求上下文的傳遞。
編譯原理并不複雜,主要是以下兩點:
- 擷取請求上下文:轉換為對 this 的引用
- 調用 Hooks:轉換為 bind 調用,将 this 傳遞下去
通過這種方式,我們在函數間對于上下文與 Hooks 的引用,串成了一條完整的調用鍊。而 bind 操作所帶來的調用開銷完全是可接受的。
由于我們是使用的 TypeScript,在編譯過程中對于源碼的更改會影響到 Source Map 的生成,是以我們也自研了 Midway 的編譯器 mwcc,不僅解決了 Source Map 生成等問題,更是提供了類似于 Babel + Babel Traverse + Plugin 的開發體驗,有興趣的同學可以自行了解一下~
漸進式開發:Progressive development
阿裡在落地 Node.js 時,會遇到非常多複雜的業務場景,這部分将向大家介紹我們在 Node.js 企業級應用開發的實踐與解決方案,及在函數式開發的場景下,如何複用這部分最佳實踐。
阿裡巴巴企業級 Node.js 應用開發實踐
在設計整個 Midway 架構時,我們一直在思考一個問題:“用什麼方式解決複雜業務問題”?而我們給出的答案是參考軟體設計的經典原則:SOLID 軟體設計原則與其中的依賴倒置原則。
同時我們也參考了諸多業界的實踐,發現成熟的 IoC 設計已經能夠解決複雜業務的問題,包括 Java 的 Spring、JS 社群的 Nest.js/TypeOrm 等,都采用了基于 IoC 的實作方式。
是以,我們決定通過自研的 IoC 架構,作為 Midway 體系的核心去解決複雜應用的維護問題。
而函數式研發作為 Midway 體系的一種解決方案,是以在設計之初我們就考慮了函數與 Midway IoC 體系的融合,使得函數式研發可以複用 IoC 的最佳實踐。
函數式與 IoC 的結合
這兒我們依然通過 Hooks 來解決這個問題。
我們提供了 useInject Api,通過這個 Hooks 在函數中來使用 IoC。
通過這種方式,我們實作了函數式與 IoC 的無縫結合,從簡單到複雜場景都能處理。
内部落地情況
Midway Serverless 的雲端一體方案在對外釋出前,在阿裡内部實際上已經探索了有大半年的時間。
項目時間軸如下
- 2020.02:Idea 提出 & POC 示範
- 2020.03:核心功能确認 & Api 确認
- 2020.04:首個業務落地
- 2020.05 - Now:多個業務落地并使用,持續疊代中
内部落地的 BU
未來展望
目前 Midway Serverless 的雲端一體方案已正式對社群釋出并可用,大家可以進入 Midway Serverless 的 Github 倉庫,檢視雲端一體方案的文檔與使用方式,覺得好用的話記得點個 Star 哦~
在阿裡巴巴内部,我們主打的是中背景與移動端的場景,但實際上這套方案是可以用于多場景的。是以在未來,我們希望能投入到開源,結合前端架構、SSR、小程式等各種場景并落地。
這部分是我們未來的一個規劃,也歡迎大家來參與開源,送出 Idea 與代碼。一同去打造更優秀的研發體驗。
雲開發Web應用訓練營雲栖返場特輯來襲
雲開發Web應用訓練營雲栖返場特輯,名額有限快搶!這個夏天最飒的camp雲栖大會期間返場,從入門到精通快速上手Serverless和雲開發技術,無需保有伺服器,輕松開發并上線自己的個人部落格、小程式、管理系統等。連續7天打卡獎勵阿裡雲飛天代碼T-shirt。
關注「Alibaba F2E」
把握阿裡巴巴前端新動向