陳富強
(廣州華商學院數(shù)據(jù)科學學院,廣州 510000)
在傳統(tǒng)開發(fā)模式中,開發(fā)一個應用程序,從開始到上線需要不同的角色來做不同的事情,溝通成本非常大,并且運維過程中需要考慮到服務器的負載均衡、事務、集群、緩存、消息傳遞和數(shù)據(jù)冗余等事情。
云計算涌現(xiàn)出很多改變傳統(tǒng)IT 架構(gòu)和運維方式的新技術(shù),比如虛擬機、容器、微服務,無論這些技術(shù)應用在哪些場景,降低成本、提升效率是云服務永恒的主題。Serverless 架構(gòu)就是在云計算背景下產(chǎn)生的,基于Serverless 架構(gòu)后端的應用被拆分成為一個個函數(shù),只需要編寫完成函數(shù)后部署到Serverless 服務即可,不用關(guān)心任何服務器的操作,大大提高了開發(fā)的效率,減少了溝通的成本。
Serverless 中文的含義是"無服務器",但是它真正的含義是開發(fā)者再也不用過多考慮服務器的問題,但是并不代表完全去除服務器,而是依靠第三方資源服務器后端,比如使用Ama?zon Web Services(AWS)Lambda 計算服務來執(zhí)行代碼。Serverless 架構(gòu)分為Backend as a Service(BaaS)和Functions as a Service(FaaS)[1]兩種技術(shù),Baas 的含義是后端即服務,它的應用架構(gòu)由大量第三方云服務器和API 組成,使用中關(guān)于服務器的邏輯和狀態(tài)都由服務提供方來管理。比如典型的單頁應用SPA 和移動APP 客戶端應用,前后端交互主要是以RestAPI 調(diào)用為主。只需要調(diào)用服務提供方的API 即可完成相應的功能,比如常見的身份驗證,云端數(shù)據(jù)/文件存儲,消息推送,應用數(shù)據(jù)分析等。
FaaS 可以被叫做:函數(shù)即服務。開發(fā)者可以直接將服務業(yè)務邏輯代碼部署、運行在第三方提供的無狀態(tài)計算容器中,開發(fā)者只需要編寫業(yè)務代碼即可,無需關(guān)注服務器,并且代碼的執(zhí)行是由事件觸發(fā)的。其中AWS Lambda是目前最佳的FaaS 實現(xiàn)之一。Serverless 是由開發(fā)者實現(xiàn)的服務端邏輯運行在無狀態(tài)的計算容器中,它是由事件觸發(fā),完全被第三方管理。
Serverless 計算是一種無需管理服務器即可構(gòu)建和部署云服務的方法[2]。與IaaS(基礎(chǔ)設(shè)施即服務)相比,Serverless 計算提供了更高級別的抽象,因此有望提供更高的開發(fā)人員生產(chǎn)力和更低的運營成本。無服務器計算的關(guān)鍵特征包括資源彈性零操作和即用即付。
最初的云服務AWS S3(Simple Storage Ser?vice)[3]是無服務器的,但僅用于存儲,實踐證明很難擴展代碼執(zhí)行。IaaS 成為主導的云服務,開發(fā)人員提供虛擬機(服務器)來部署應用程序。開發(fā)者負責規(guī)劃、配置、部署和維護服務器,即使是更高級的PaaS(平臺即服務),開發(fā)者也只是獲得了預裝軟件堆棧的虛擬服務器,必須根據(jù)分配的資源付費(例如CPU 和內(nèi)存),而不是實際使用情況付費。
近年來,由AWS lambda 首創(chuàng)的新一代云服務使開發(fā)人員能夠直接基于代碼功能創(chuàng)建Web服務。開發(fā)人員無需配置或管理服務器,云提供商在請求到來時自動部署執(zhí)行環(huán)境,并根據(jù)運行的需求擴展執(zhí)行環(huán)境,這種方法被稱為功能即服務(FaaS)。行業(yè)報告表明,F(xiàn)aaS 已經(jīng)受到云計算用戶的歡迎,并可能成為未來云計算的主導形式。
FaaS 的興起得益于虛擬化和容器化技術(shù)的進步,這可以讓開發(fā)者以最小的開銷頻繁啟動和停止執(zhí)行環(huán)境。領(lǐng)先的公共云提供商使用系統(tǒng)虛擬機和應用程序容器的組合作為FaaS 的基礎(chǔ)設(shè)施。與系統(tǒng)虛擬機相比,Docker 等應用容器更快更輕[2],但安全性相較于虛擬機要低。
在當前主流的FaaS 應用中,AWS Lambda是基于一種名為Firecracker 的輕量級虛擬化技術(shù)。Firecracker也稱為micro VM,比傳統(tǒng)系統(tǒng)虛擬機更輕、更快,因此適用于Faas 工作負載;IBM Cloud 功能利用Docker 容器提供隔離;微軟Azure[4]功能兼容Docker,但部署在公有云時增加了虛擬機保護;谷歌云功能采用了一種折衷的方法,其g Visor 引擎主要目的是在公共云中安全運行Docker。然而,g Visor 引擎比普通Docker慢2倍。
即使有那些性能優(yōu)化的系統(tǒng)虛擬機和應用程序容器,F(xiàn)aaS仍然存在性能和擴展性問題:
一是冷啟動慢。配置和啟動micro VM 或容器可能需要幾秒鐘,其中每個函數(shù)執(zhí)行都可能需要一個新的micro VM 或容器,此問題還會導致不一致的問題和可能出現(xiàn)一些不可預測的運行結(jié)果,因為函數(shù)的執(zhí)行可能還要比運行環(huán)境的啟動更快一些。
其次,虛擬機或容器必須為每個函數(shù)調(diào)用設(shè)置一個運行時軟件堆棧,包括不同操作系統(tǒng)的標準庫。這是一種很大的資源消耗。
最后,虛擬機或容器只能測量粗粒度的資源消耗,例如使用的分配內(nèi)存和執(zhí)行時間。而它們不支持基于準確CPU 執(zhí)行周期的細粒度使用計費。
在本文中,將討論一種不依賴于虛擬機和容器的FaaS方法。
Serverless 中文的含義是"無服務器",但是它真正的含義是開發(fā)者再也不用過多考慮服務器的問題[1],但是并不代表完全去除服務器,而是依靠第三方資源服務器后端。
在現(xiàn)階段,Serverless 主要應用在以下幾個場景:在Web 及移動端服務中,可以整合API網(wǎng)關(guān)和Serverles 服務構(gòu)建Web 及移動后端,幫助開發(fā)者構(gòu)建可彈性擴展、高可用的移動或Web 后端應用服務;在IoT 場景下可高效地處理實時流數(shù)據(jù),由設(shè)備產(chǎn)生海量的實時信息流數(shù)據(jù),通過Serverles 服務分類處理并寫入后端處理。另外在實時媒體資訊內(nèi)容處理場景里,用戶上傳的音視頻到對象存儲OBS,通過上傳事件觸發(fā)多個函數(shù),分別完成高清轉(zhuǎn)碼、音頻轉(zhuǎn)碼等功能,滿足用戶對實時性和并發(fā)能力的高要求。無服務器計算還適合于任何事件驅(qū)動的各種不同的用例,這包括物聯(lián)網(wǎng)、移動應用,基于網(wǎng)絡(luò)的應用程序和聊天機器人等。
場景一:應用負載有顯著的波峰波谷
Serverless 應用成功與否的評判標準并不是公司規(guī)模的大小,而是其業(yè)務背后的具體技術(shù)問題,比如業(yè)務波峰波谷明顯,如何實現(xiàn)削峰填谷。一個公司的業(yè)務負載具有波峰波谷時,機器資源要按照峰值需求預估;而在波谷時期機器利用率則明顯下降,這是因為不能進行資源復用而導致的浪費。
業(yè)界普遍共識是,當自有機器的利用率小于30%,使用Serverless后會有顯著的效率提升。對于云服務廠商,在具備了足夠多的用戶之后,各種波峰波谷疊加后平穩(wěn)化,聚合之后資源復用性更高。比如,外賣企業(yè)負載高峰是在用餐時期,安防行業(yè)的負載高峰則是夜間,這是受各個企業(yè)業(yè)務定位所限的;而對于一個成熟的云服務廠商,如果其平臺足夠大,用戶足夠多,是不應該有明顯的波峰波谷現(xiàn)象的。
場景二:典型用例-基于事件的數(shù)據(jù)處理
視頻處理的后端系統(tǒng),常見功能需求如下:視頻轉(zhuǎn)碼、抽取數(shù)據(jù)、人臉識別等,這些均為通用計算任務,可由函數(shù)計算執(zhí)行。
開發(fā)者需要自己寫出實現(xiàn)邏輯,再將任務按照控制流連接起來,每個任務的具體執(zhí)行由云廠商來負責。如此,開發(fā)變得更便捷,并且構(gòu)建的系統(tǒng)天然高可用、實時彈性伸縮,用戶不需要關(guān)心機器層面問題。
對于企業(yè)來說,支持Serverless 計算的平臺可以節(jié)省大量時間和成本,同時可以減輕員工負擔,讓開發(fā)者得以開展更有價值的工作。另一方面可以提高敏捷度,更快速地推出新應用和新服務,進而提高客戶滿意度。
但是Serverless 對應用來說不是完美的,存在以下問題:
(1)不適合長時間運行應用
Serverless 只有在請求到來時才運行。當應用不運行時就會進入“休眠狀態(tài)”,下次當請求來臨時,應用將會需要一個啟動時間,即冷啟動時間。如果應用需要一直長期不間斷的運行、處理大量的請求,那么可能就不適合采用Serverless 架構(gòu)。如果通過CRON 的方式或者CloudWatch 來定期喚醒應用,又會比較消耗資源。這就需要對Serverless 架構(gòu)做優(yōu)化,如果頻繁調(diào)用,這個資源將會常駐內(nèi)存,第一次冷啟動之后,就可以一直服務,直到一段時間內(nèi)沒有新的調(diào)用請求進來,才會轉(zhuǎn)入“休眠”狀態(tài),甚至被回收,從而不消耗任何資源。
(2)完全依賴于第三方服務
當企業(yè)云環(huán)境已經(jīng)有大量的基礎(chǔ)設(shè)施時,Serverless 對于應用來說并不是一個好的解決方案。當采用某云服務廠商的Serverless 架構(gòu)時,應用就和該服務供應商綁定了,那么再將服務遷到別的云服務商上就沒有那么容易。因此項目需要修改一下系列的底層代碼,而能采取的應對方案,便是建立隔離層。建立隔離層意味著在設(shè)計應用的時候,就需要隔離API 網(wǎng)關(guān)、隔離數(shù)據(jù)庫層,市面上還沒有成熟的ORM 工具,既支持Firebase,又支持DynamoDB 等,這些也將帶來一些額外的成本,可能帶來的問題會比解決的問題多。
(3)缺乏調(diào)試和開發(fā)工具
每次當項目需要調(diào)試時,需要一遍又一遍地上傳代碼。每次上傳的時候,像是在部署服務器,并不能總是快速地定位出問題在哪。針對這個問題,項目可以使用一個類似于log4j 的可以分級別記錄日志的Node.js 庫winston??芍С謊rror、warn、info、verbose、debug、silly 六個不同級別的日志,再結(jié)合大數(shù)據(jù)進行日志分析過濾,快速定位問題。
(4)構(gòu)建復雜
Serverless 很便宜,但構(gòu)建起來并不簡單。AWS Lambda 的Cloud Formation 配置非常復雜且難以實現(xiàn)及編寫(JSON 格式),雖然Cloud For?mation提供了Template模板,但想要在項目中使用的話,需要創(chuàng)建一個規(guī)定的Stack,在Stack中指定要使用的模板Template,然后AWS 才會按照Template中的定義來創(chuàng)建及初始化資源。
而Serverless Framework 的配置相對簡單,采用的是YAML 格式。在部署的時候,Server?less Framework 會根據(jù)配置生成Cloud Formation配置。然而這也并非是一個真正用于生產(chǎn)的配置,真實的應用場景遠遠比這復雜。
WebAssembly(縮寫為wasm)是一種使用非JavaScript代碼,并使其在瀏覽器中運行的方法。這些代碼可以是C、C++或Rust 等。它們會被編譯進瀏覽器,在CPU 上以接近原生的速度運行。這些代碼的形式是二進制文件,可以直接在JavaScript 中將它們當作模塊來用。WebAs?sembly 不能替代Javascript,相反,這兩種技術(shù)是相輔相成的。通過JavaScriptAPI,可以將WebAssembly 模塊加載到頁面中。也就是說,可以通過WebAssembly 來充分利用編譯代碼的性能,同時保持JavaScript 的靈活性。WebAs?sembly 的使用場景遠不止于適用于Web 瀏覽器,還適用于各種需要提升運行性能的場景。此外,WebAssembly 不是編程語言,而是一種中間格式,叫字節(jié)碼,可以作為其他語言的編譯目標。
WebAssembly 是一種新的字節(jié)碼格式,主流瀏覽器都已經(jīng)支持WebAssembly。和JS 需要解釋執(zhí)行不同的是,WebAssembly 字節(jié)碼和底層機器碼很相似,可快速裝載運行,因此性能相對于JS 解釋執(zhí)行大大提升。換言之,WebAs?sembly 并不是一門編程語言,而是一份字節(jié)碼標準,需要用高級編程語言編譯出字節(jié)碼放到WebAssembly虛擬機中才能運行。
盡管WebAssembly 是為運行在Web 上設(shè)計的,但它也可以在其它的環(huán)境中良好地運行。包括從用作測試的最小化shell,到完整的應用環(huán)境——例如:在數(shù)據(jù)中心的服務器、物聯(lián)網(wǎng)(IoT)設(shè)備或者是移動桌面應用程序。甚至,運行嵌入在較大程序里也是可行的。
非Web 環(huán)境下,它有和Web 環(huán)境下不同的應用編程接口(API)。功能測試(feature testing)和動態(tài)鏈接(dynamic linking)會使其可自發(fā)現(xiàn)、易于使用。非Web 環(huán)境可能包括JavaScript 虛擬機(例如node.js)。但是,WebAssembly也被設(shè)計為能夠在沒有JavaScript虛擬機的情況下運行。
WebAssembly 標準本身不會嘗試定義任何大型可移植的類庫。然而,作為WebAssembly語義核心庫中的函數(shù)的某些功能,將以原始操作符(primitive operators)的身份,成為核心WebAs?sembly 標準的一部分。對于在Web 和流行的非Web 環(huán)境之間存在重疊的地方,將會有共享的規(guī)范。
為了保證多數(shù)情況下可運行性,源碼級別的可移植性。開源社區(qū)將會構(gòu)建從源碼級別的接口,映射到主機環(huán)境內(nèi)置功能的庫(在運行時或構(gòu)建時)。WebAssembly 會提供原始構(gòu)建塊:包括功能測試(featuretesting)、內(nèi)建模塊(built?ingmodules)以及動態(tài)加載(dynamicloading)。早期已經(jīng)應用WebAssembly 構(gòu)建功能庫的例子是POSIX 和SDL。因為WebAssembly 支持C/C++級語義,不需要WebAPI 的非Web 路徑,WebAs?sembly 能夠在許多平臺上用作便攜式的二進制格式,為移植性、工具和語言無關(guān)性提供了很強的便利性。
Serverless FaaS 必須為用戶提交和不受信任的代碼提供安全和隔離的執(zhí)行環(huán)境。本文提出基于Webassembly 設(shè)計是FaaS 的一種更輕、更快的替代方案。與系統(tǒng)虛擬機和Docker 容器不同,WebAssembly 是一種字節(jié)碼格式,可以將高級語言編譯成機器語言。
WebAssembly 最初是為了提高Web 瀏覽器內(nèi)的JavaScript 性能。由于它原本設(shè)計成執(zhí)行從Web 下載的代碼,出于安全考慮,WebAssembly運行的過程中為不受信任的代碼提供了基于軟件的故障隔離(SFI)沙箱。
WebAssembly 支持多種編程語言,例如C/C++和Rust。WebAssembly 系統(tǒng)接口標準允許WebAssembly 運行時與操作系統(tǒng)資源接口,這使其適用于服務器端應用程序。WebAssembly可以安全地運行,并且可以在不同的底層平臺上按需啟動和停止這些功能,而無需更改任何代碼。由于WebAssembly 在操作碼級別提供抽象,因此它可以在運行時精確測量細粒度的資源消耗。
WebAssembly 相對于系統(tǒng)虛擬機、micro VM和Docker 容器的最重要優(yōu)勢是性能較好和占用空間較小。一些云提供商,例如Fastly 和Cloud?flare,已經(jīng)在其邊緣網(wǎng)絡(luò)上提供基于WebAssem?bly的FaaS服務。在本研究中,以Docker容器為基準評估WebAssembly 運行時的性能,之所以選擇Docker 作為基準比較,是因為Docker 代表了非WebAssembly的FaaS服務的最佳性能。
WebAssembly 在FaaS 中相對 于Docker 的性能優(yōu)勢已在文獻[5]中有所記載。本文研究有幾個明顯的差異,即本研究不是對集成用例進行計時,而是評估標準性能基準,例如多線程效率或磁盤I/O。此外,還使用不同的優(yōu)化策略評估了WebAssembly運行性能。
本文在兩個大型云平臺阿里云ECS 和騰訊云CVM 上進行了實驗。兩臺主機上都運行Ubuntu linux 20.04tls。硬件配置如下:
ECS:Intel cpu 2.30GHz with 8 cores and 32 GB of RAM;
CVM:Intel cpu 2.50GHz with 4 cores and 16 GB of RAM。
評估以下運行環(huán)境:
最新的穩(wěn)定版docker 版本v19.03.8。一個Ubuntu linux18.04 的Docker 鏡像用于啟動docker容器。
V8,V8.1.307,是google 開發(fā)的WebAssem?bly 運行時環(huán)境,它被預裝在許多網(wǎng)絡(luò)瀏覽器中。
WAVM,nightly/2020-05-28,是由Andrew Scheidecke 領(lǐng)導的一項協(xié)作項目,旨在支持瀏覽器之外的WebAssembly。
對于每個測試機器和運行時組合,運行了以下基準測試。每個測試50 次,并取完成時間的平均值和標準偏差。源代碼和說明在GitHub上公開提供[6]。
(1)nop 測試,啟動運行時環(huán)境并退出。該測試評估冷啟動性能。
(2)cat-sync 測試打開一個本地文件進行讀取并退出。它評估進行操作系統(tǒng)調(diào)用的性能。
(3)CLBG 測試,以下3 個測試標準來自Computer Languages Benchmarks Game[7],該測試為超過25 種編程語言提供眾包基準程序,每個測試均計算運行時間:
fannkuch-redux,重復12次,測量索引訪問到一個整數(shù)序列。
mandelbrot,重復15000 次,就是生成Man?delbrot集可移植位圖文件。
binary-tree,重復21 次,分配和釋放大量二叉樹。
所有基準測試都是用C 編寫的。對于Docker 測試,測試源代碼由llvmv 10.0.0 工具鏈編譯為本機二進制文件。對于WebAssembly 測試,使用Emscripten SDK v1.39.17 將源代碼編譯為WebAssembly字節(jié)碼。
圖1 顯示了nop 測試WebAssembly 冷啟動的執(zhí)行時間,結(jié)果至少比Docker 快10 倍。WebAs?sembly 和V8 的啟動時間都不到docker 啟動時間的1/500。
圖1 冷啟動時間
圖2 顯示了cat-sync 測試的執(zhí)行時間結(jié)果,WebAssembly 運行時至少比Docker 快10 倍。其中WebAssembly 表現(xiàn)出最好的性能。Docker 打開文件所需的時間是WebAssembly 的10 到15倍。
圖2 打開和讀取文件時間
表1 顯示了3 個計算基準的執(zhí)行時間結(jié)果。WebAssembly運行時比docker快10%到50%。
表1 基準測試執(zhí)行時間 單位:秒
除了執(zhí)行時間性能優(yōu)勢之外,WebAssembly的占用空間也比Docker小得多,Ubuntu 18.04的docker 映像為188 MB。一般來說,Webassembly運行時是FaaS的完整Docker鏡像大小的1/10。
雖然WebAssembly 運行時在基準測試中的表現(xiàn)優(yōu)于Docker,但也存在許多可能阻礙其應用的挑戰(zhàn)。
首先,WebAssembly 上的編程語言支持是有限的。雖然LLVM 工具鏈理論上支持從20 多種語言生成Webassembly 字節(jié)碼,但在實踐中只有少數(shù)幾種語言得到很好的支持。目前,C/C++、Rust 和Assembly Script 是支持WebAs?sembly 的最好的編程語言,這意味著開發(fā)人員如果需要使用基于WebAssembly 的FaaS 服務,就需要用這些語言編寫相應的函數(shù),來執(zhí)行需要的結(jié)果[8]。
其次,與容器docker 和微型虛擬機相比,WebAssembly 具有不同的模型來訪操作系統(tǒng)。WebAssembly 可以訪問一些系統(tǒng)特性,例如網(wǎng)絡(luò)和多線程管理,因為WebAssembly 對這些資源的訪問受高級安全策略的約束(即基于能力的安全性),所以可以兼具高性能和安全性。在本研究中,除了簡單的文件操作之外,并沒有評估WebAssembly 運行時的性能。多線程I/O 是當前應用程序的一個重要方面,隨著相關(guān)Webas?sembly規(guī)范的成熟,多線程I/O將是未來研究的主題[9]。
最后,目前沒有針對WebAssembly 運行時的行業(yè)標準管理和編排工具。大多數(shù)使用自主開發(fā)的解決方案來按需啟動和停止WebAssem?bly 運行時環(huán)境。未來預計隨著WebAssembly 使用率的增加,此類編排管理工具將會出現(xiàn)。