被吹得天花乱坠的无服务器架构,究竟是什么?
戳藍(lán)字“CSDN云計(jì)算”關(guān)注我們哦!
無服務(wù)器計(jì)算(Severless computing,簡稱 Serverless)現(xiàn)在是軟件架構(gòu)圈中的熱門話題,國外三大云計(jì)算供應(yīng)商(Amazon、Google 和 Microsoft)都在大力投入這個領(lǐng)域,涌現(xiàn)了不計(jì)其數(shù)的相關(guān)書籍、開源框架、商業(yè)產(chǎn)品、技術(shù)大會。到底什么是 Serverless?它有什么長處/短處?我希望通過本文對這些問題提供一些啟發(fā)。
一些示例
界面驅(qū)動的應(yīng)用(UI-driven applications)
我們來設(shè)想一個傳統(tǒng)的三層 C/S 架構(gòu),例如一個常見的電子商務(wù)應(yīng)用(比如在線寵物商店),假設(shè)它服務(wù)端用 Java,客戶端用 HTML/JavaScript:
在這個架構(gòu)下客戶端通常沒什么功能,系統(tǒng)中的大部分邏輯——身份驗(yàn)證、頁面導(dǎo)航、搜索、交易——都在服務(wù)端實(shí)現(xiàn)。
把它改造成 Serverless 架構(gòu)的話會是這樣:
這是張大幅簡化的架構(gòu)圖,但還是有相當(dāng)多變化之處:
我們移除了最初應(yīng)用中的身份驗(yàn)證邏輯,換用一個第三方的 BaaS 服務(wù)。
另一個 BaaS 示例:我們允許客戶端直接訪問一部分?jǐn)?shù)據(jù)庫內(nèi)容,這部分?jǐn)?shù)據(jù)完全由第三方托管(如 AWS Dynamo),這里我們會用一些安全配置來管理客戶端訪問相應(yīng)數(shù)據(jù)的權(quán)限。
前面兩點(diǎn)已經(jīng)隱含了非常重要的第三點(diǎn):先前服務(wù)器端的部分邏輯已經(jīng)轉(zhuǎn)移到了客戶端,如保持用戶 Session、理解應(yīng)用的 UX 結(jié)構(gòu)(做頁面導(dǎo)航)、獲取數(shù)據(jù)并渲染出用戶界面等等??蛻舳藢?shí)際上已經(jīng)在逐步演變?yōu)閱雾搼?yīng)用。
還有一些任務(wù)需要保留在服務(wù)器上,比如繁重的計(jì)算任務(wù)或者需要訪問大量數(shù)據(jù)的操作。這里以“搜索”為例,搜索功能可以從持續(xù)運(yùn)行的服務(wù)端中拆分出來,以 FaaS 的方式實(shí)現(xiàn),從 API 網(wǎng)關(guān)(后文做詳細(xì)解釋)接收請求返回響應(yīng)。這個服務(wù)器端函數(shù)可以和客戶端一樣,從同一個數(shù)據(jù)庫讀取產(chǎn)品數(shù)據(jù)。我們原始的服務(wù)器端是用 Java 寫的,而 AWS Lambda(假定我們用的這家 FaaS 平臺)也支持 Java,那么原先的搜索代碼略作修改就能實(shí)現(xiàn)這個搜索函數(shù)。
最后我們還可以把“購買”功能改寫為另一個 FaaS 函數(shù),出于安全考慮它需要在服務(wù)器端,而非客戶端實(shí)現(xiàn)。它同樣經(jīng)由 API 網(wǎng)關(guān)暴露給外部使用。
消息驅(qū)動的應(yīng)用(Message-driven applications)
再舉一個后端數(shù)據(jù)處理服務(wù)的例子。假設(shè)你在做一個需要快速響應(yīng) UI 的用戶中心應(yīng)用,同時你又想捕捉記錄所有的用戶行為。設(shè)想一個在線廣告系統(tǒng),當(dāng)用戶點(diǎn)擊了廣告你需要立刻跳轉(zhuǎn)到廣告目標(biāo),同時你還需要記錄這次點(diǎn)擊以便向廣告客戶收費(fèi)(這個例子并非虛構(gòu),我的一位前同事最近就在做這項(xiàng)重構(gòu))。
傳統(tǒng)的架構(gòu)會是這樣:“廣告服務(wù)器”同步響應(yīng)用戶的點(diǎn)擊,同時發(fā)送一條消息給“點(diǎn)擊處理應(yīng)用”,異步地更新數(shù)據(jù)庫(例如從客戶的賬戶里扣款)。
在 Serverless 架構(gòu)下會是這樣:
這里兩個架構(gòu)的差異比我們上一個例子要小很多。我們把一個長期保持在內(nèi)存中待命的任務(wù)替換為托管在第三方平臺上以事件驅(qū)動的 FaaS 函數(shù)。注意這個第三方平臺提供了消息代理和 FaaS 執(zhí)行環(huán)境,這兩個緊密相關(guān)的系統(tǒng)。
解構(gòu) “Function as a Service”
我們已經(jīng)提到多次 FaaS 的概念,現(xiàn)在來挖掘下它究竟是什么含義。先來看看 Amazon 的 Lambda 產(chǎn)品簡介:
通過 AWS Lambda,無需配置或管理服務(wù)器(1)即可運(yùn)行代碼。您只需按消耗的計(jì)算時間付費(fèi) – 代碼未運(yùn)行時不產(chǎn)生費(fèi)用。借助 Lambda,您幾乎可以為任何類型的應(yīng)用程序或后端服務(wù)(2)運(yùn)行代碼,而且全部無需管理。只需上傳您的代碼,Lambda 會處理運(yùn)行(3)和擴(kuò)展高可用性(4)代碼所需的一切工作。您可以將您的代碼設(shè)置為自動從其他 AWS 服務(wù)(5)觸發(fā),或者直接從任何 Web 或移動應(yīng)用程序(6)調(diào)用。
本質(zhì)上 FaaS 就是無需配置或管理你自己的服務(wù)器系統(tǒng)或者服務(wù)器應(yīng)用即可運(yùn)行后端代碼,其中第二項(xiàng)——服務(wù)器應(yīng)用——是個關(guān)鍵因素,使其區(qū)別于現(xiàn)今其他一些流行的架構(gòu)趨勢如容器或者 PaaS(Platform as a Service)?;仡櫱懊纥c(diǎn)擊處理的例子,FaaS 替換掉了點(diǎn)擊處理服務(wù)器(可能跑在一臺物理服務(wù)器或者容器中,但絕對是一個獨(dú)立的應(yīng)用程序),它不需要服務(wù)器,也沒有一個應(yīng)用程序在持續(xù)運(yùn)行。
FaaS 不需要代碼基于特定的庫或框架,從語言或環(huán)境的層面來看 FaaS 就是一個普通的應(yīng)用程序。例如 AWS Lambda 支持 JavaScript、Python 以及任意 JVM 語言(Java、Clojure、Scala 等),并且你的 FaaS 函數(shù)還可以調(diào)用任何一起部署的程序,也就是說實(shí)際上你可以用任何能編譯為 Unix 程序的語言(稍后我們會講到 Apex)。FaaS 也有一些不容忽視的局限,尤其是牽涉到狀態(tài)和執(zhí)行時長問題,這些我們稍后詳談。 再次回顧一下點(diǎn)擊處理的例子——代碼遷移到 FaaS 唯一需要修改的是 main 方法(啟動)的部分,刪掉即可,也許還會有一些上層消息處理的代碼(實(shí)現(xiàn)消息監(jiān)聽界面),不過這很可能只是方法簽名上的小改動。所有其他代碼(比如那些訪問數(shù)據(jù)庫的)都可以原樣用在 FaaS 中。
既然我們沒有服務(wù)器應(yīng)用要執(zhí)行,部署過程也和傳統(tǒng)的方式大相徑庭——把代碼上傳到 FaaS 平臺,平臺搞定所有其他事情。具體而言我們要做的就是上傳新版的代碼(zip 文件或者 jar 包)然后調(diào)用一個 API 來激活更新。
橫向擴(kuò)展是完全自動化、彈性十足、由 FaaS 平臺供應(yīng)商管理的。如果你需要并行處理 100 個請求,不用做任何處理系統(tǒng)可以自然而然地支持。FaaS 的“運(yùn)算容器”會在運(yùn)行時按需啟動執(zhí)行函數(shù),飛快地完成并結(jié)束。 回到我們的點(diǎn)擊處理應(yīng)用,假設(shè)某個好日子我們的客戶點(diǎn)擊廣告的數(shù)量有平日的十倍之多,我們的點(diǎn)擊處理應(yīng)用能承載得住么?我們寫的代碼是否支持并行處理?支持的話,一個運(yùn)行實(shí)例能夠處理這么多點(diǎn)擊量嗎?如果環(huán)境允許多進(jìn)程執(zhí)行我們能自動支持或者手動配置支持嗎?以 FaaS 實(shí)現(xiàn)你的代碼需要一開始就以并行執(zhí)行為默認(rèn)前提,但除此之外就沒有其他要求了,平臺會完成所有的伸縮性需求。
FaaS 中的函數(shù)通常都由平臺指定的一些事件觸發(fā)。在 AWS 上有 S3(文件)更新、時間(定時任務(wù))、消息總線(Kinesis)消息等,你的函數(shù)需要指定監(jiān)聽某個事件源。在點(diǎn)擊處理器的例子中我們有個假設(shè)是已經(jīng)采用了支持 FaaS 訂閱的消息代理,如果沒有的話這部分也需要一些代碼量。
大部分的 FaaS 平臺都支持 HTTP 請求觸發(fā)函數(shù)執(zhí)行,通常都是以某種 API 網(wǎng)關(guān)的形式實(shí)現(xiàn)(如 AWS API Gateway,Webtask)。我們在寵物商店的例子中就以此來實(shí)現(xiàn)搜索和購買功能。
狀態(tài)
當(dāng)牽涉到本地(機(jī)器或者運(yùn)行實(shí)例)狀態(tài)時 FaaS 有個不能忽視的限制。簡單點(diǎn)說就是你需要接受這么一個預(yù)設(shè):函數(shù)調(diào)用中創(chuàng)建的所有中間狀態(tài)或環(huán)境狀態(tài)都不會影響之后的任何一次調(diào)用。這里的狀態(tài)包括了內(nèi)存數(shù)據(jù)和本地磁盤存儲數(shù)據(jù)。從部署的角度換句話說就是 FaaS 函數(shù)都是無狀態(tài)的(Stateless)。
這對于應(yīng)用架構(gòu)有重大的影響,無獨(dú)有偶,“Twelve-Factor App” 的概念也有一模一樣的要求。
在此限制下的做法有多種,通常這個 FaaS 函數(shù)要么是天然無狀態(tài)的——純函數(shù)式地處理輸入并且輸出,要么使用數(shù)據(jù)庫、跨應(yīng)用緩存(如 Redis)或者網(wǎng)絡(luò)文件系統(tǒng)(如 S3)來保存需要進(jìn)一步處理的數(shù)據(jù)。
執(zhí)行時長
FaaS 函數(shù)可以執(zhí)行的時間通常都是受限的,目前 AWS Lambda 函數(shù)執(zhí)行最長不能超過五分鐘,否則會被強(qiáng)行終止。
這意味著某些需要長時間執(zhí)行的任務(wù)需要調(diào)整實(shí)現(xiàn)方法才能用于 FaaS 平臺,例如你可能需要把一個原先長時間執(zhí)行的任務(wù)拆分成多個協(xié)作的 FaaS 函數(shù)來執(zhí)行。
啟動延遲
目前你的 FaaS 函數(shù)響應(yīng)請求的時間會受到大量因素的影響,可能從 10 毫秒到 2 分鐘不等。這聽起來很糟糕,不過我們來看看具體的情況,以 AWS Lambda 為例。
如果你的函數(shù)是 JavaScript 或者 Python 的,并且代碼量不是很大(千行以內(nèi)),執(zhí)行的消耗通常在 10 到 100 毫秒以內(nèi),大函數(shù)可能偶爾會稍高一些。
如果你的函數(shù)實(shí)現(xiàn)在 JVM 上,會偶爾碰到 10 秒以上的 JVM 啟動時間,不過這只會在兩種情況下發(fā)生:
你的函數(shù)調(diào)用觸發(fā)比較稀少,兩次調(diào)用間隔超過 10 分鐘。
流量突發(fā)峰值,比如通常每秒處理 10 個請求的任務(wù)在 10 秒內(nèi)飆升到每秒 100 個。
前一種情況可以用個 hack 來解決:每五分鐘 ping 一次給函數(shù)保持熱身。
這些問題嚴(yán)重么?這要看你的應(yīng)用類型和流量特征。我先前的團(tuán)隊(duì)有一個 Java 的異步消息處理 Lambda 應(yīng)用每天處理數(shù)億條消息,他們就完全不擔(dān)心啟動延遲的問題。如果你要寫的是一個低延時的交易程序,目前而言肯定不會考慮 FaaS 架構(gòu),無論你是用什么語言。
不論你是否認(rèn)為你的應(yīng)用會受此影響,都應(yīng)該以生產(chǎn)環(huán)境級別的負(fù)載測試下實(shí)際性能情況。如果目前的情況還不能接受的話,可以幾個月后再看看,因?yàn)檫@也是現(xiàn)在的 FaaS 平臺供應(yīng)商們主要集中精力在解決的問題。
API 網(wǎng)關(guān)
我們前面還碰到過一個 FaaS 的概念:“API 網(wǎng)關(guān)”。API 網(wǎng)關(guān)是一個配置了路由的 HTTP 服務(wù)器,每個路由對應(yīng)一個 FaaS 函數(shù),當(dāng) API 網(wǎng)關(guān)收到請求時它找到匹配請求的路由,調(diào)用相應(yīng)的 FaaS 函數(shù)。通常 API 網(wǎng)關(guān)還會把請求參數(shù)轉(zhuǎn)換成 FaaS 函數(shù)的調(diào)用參數(shù)。最后 API 網(wǎng)關(guān)把 FaaS 函數(shù)執(zhí)行的結(jié)果返回給請求來源。
AWS 有自己的一套 API 網(wǎng)關(guān),其他平臺也大同小異。
除了純粹的路由請求,API 網(wǎng)關(guān)還會負(fù)責(zé)身份認(rèn)證、輸入?yún)?shù)校驗(yàn)、響應(yīng)代碼映射等,你可能已經(jīng)敏銳地意識到這是否合理,如果你有這個考慮的話,我們待會兒就談。
另一個應(yīng)用 API 網(wǎng)關(guān)加 FaaS 的場景是創(chuàng)建無服務(wù)器的 http 前端微服務(wù),同時又具備了 FaaS 函數(shù)的伸縮性、管理便利等優(yōu)勢。
目前 API 網(wǎng)關(guān)的相關(guān)工具鏈還不成熟,盡管這是可行的但也要夠大膽才能用。
工具鏈
前面關(guān)于工具鏈還不成熟的說法是指大體上 FaaS 無服務(wù)器架構(gòu)平臺的情況,也有例外,Auth0 Webtask 就很重視改善開發(fā)者體驗(yàn),Tomasz Janczuk 在最近一屆的 Serverless Conf 上做了精彩的展示。
無服務(wù)器應(yīng)用的監(jiān)控和調(diào)試還是有點(diǎn)棘手,我們會在本文未來的更新中進(jìn)一步探討這方面。
開源
無服務(wù)器 FaaS 的一個主要好處就是只需要近乎透明的運(yùn)行時啟動調(diào)度,所以這個領(lǐng)域不像 Docker 或者容器領(lǐng)域那么依賴開源實(shí)現(xiàn)。未來肯定會有一些流行的 FaaS / API 網(wǎng)關(guān)平臺實(shí)現(xiàn)可以跑在私有服務(wù)器或者開發(fā)者工作站上,IBM 的 OpenWhisk 就是一個這樣的實(shí)現(xiàn),不知道它是否能成為流行選擇,接下來的時間里肯定會有更多競爭者出現(xiàn)。
除了運(yùn)行時的平臺實(shí)現(xiàn),還是有不少開源工具用以輔助開發(fā)和部署的,例如 Serverless Framework 在 API 網(wǎng)關(guān) + Lambda 的易用性上就比它的原創(chuàng)者 AWS 要好很多,這是一個 JS 為主的項(xiàng)目,如果你在寫一個 JS 網(wǎng)關(guān)應(yīng)用一定要去了解下。
再如 Apex——“輕松創(chuàng)建、部署及管理 AWS Lambda 函數(shù)”。Apex 有意思的一點(diǎn)是它允許你用 AWS 平臺并不直接支持的語言來實(shí)現(xiàn) Lambda 函數(shù),比如 Go。
什么不是 Serverless
在前文中我定義了 “Serverless” 是兩個概念的組合:“Backend as a Service” 和 “Function as a Service”,并且對后者的特性做了詳細(xì)解釋。
在我們開始探討它的好處和弊端之前,我想再花點(diǎn)兒時間在它的定義上,或者說:區(qū)分開那些容易和 Serverless 混淆的概念。我看到一些人(包括我自己最近)對此都有困惑,我想值得對此做個澄清。
對比 PaaS
既然 Serverless FaaS 這么像 12-Factor 應(yīng)用,那不就是另一種形式的 Platform as a Service 么?就像 Heroku?對此借用 Adrian Cockcroft 一句非常簡明的話:
如果你的 PaaS 能在 20ms 內(nèi)啟動一個只運(yùn)行半秒鐘的實(shí)例,它就叫 Serverless。— Adrian Cockcroft
換句話說,大部分 PaaS 應(yīng)用不會為了每個請求都啟動并結(jié)束整個應(yīng)用,而 FaaS 就是這么做的。
好吧,然而假設(shè)我是個嫻熟的 12-Factor 應(yīng)用開發(fā)者,寫代碼的方式還是沒有區(qū)別對么?沒錯,但是你如何運(yùn)維是有很大不同的。鑒于我們都是 DevOps 工程師我們會在開發(fā)階段就充分考慮運(yùn)維,對吧?
FaaS 和 PaaS 在運(yùn)維方面的關(guān)鍵區(qū)別是伸縮性(Scaling)。對于大多數(shù) PaaS 平臺而言你需要考慮如何伸縮,例如在 Heroku 上你要用到多少 Dyno 實(shí)例?對于 FaaS 應(yīng)用這一步驟是完全透明的。即便你將 PaaS 配置為自動伸縮,也無法精細(xì)到單個請求級別,除非你有一個非常明確穩(wěn)定的流量曲線可以針對性地配置。所以 FaaS 應(yīng)用在成本方面要高效得多。
既然如此,何必還用 PaaS?有很多原因,最主要的因素應(yīng)該是工具鏈成熟度。另外像Cloud Foundry 能夠給混合云和私有云的開發(fā)提供一致體驗(yàn),在寫就本文的時候 FaaS 還沒有這么成熟的平臺。
對比 NoOps
Serverless 并非“零運(yùn)維”——盡管它可能是“無系統(tǒng)管理員”,也要看你在這個 Serverless 的道路走多深。
“運(yùn)維”的意義遠(yuǎn)不止系統(tǒng)管理,它還包括并不限于監(jiān)控、部署、安全、網(wǎng)絡(luò)、支持、生產(chǎn)環(huán)境調(diào)試以及系統(tǒng)伸縮。這些事務(wù)同樣存在于 Serverless 應(yīng)用中,你仍舊需要相應(yīng)的方法處理它們。某些情況下 Serverless 的運(yùn)維會更難一些,畢竟它還是個嶄新的技術(shù)。
系統(tǒng)管理的工作仍然要做,你只是把它外包給了 Serverless 環(huán)境。這既不能說壞也不能說好——我們外包了大量的內(nèi)容,是好是壞要看具體情況。不論怎樣,某些時候這層抽象也會發(fā)生問題,就會需要一個來自某個地方的人類系統(tǒng)管理員來支持你的工作了。
對比存儲過程即服務(wù)
還有一種說法把 Serverless FaaS 看做“存儲過程即服務(wù)(Stored Procedures as a Service)”,我想原因是很多 FaaS 函數(shù)示范都用數(shù)據(jù)庫訪問作為例子。如果這就是它的主要用途,我想這個名字也不壞,但終究這只是 FaaS 的一種用例而已,這樣去考慮 FaaS 局限了它的能力。
我好奇 Serverless 會不會最終變成類似存儲過程那樣的東西,開始是個好主意,然后迅速演變成大規(guī)模技術(shù)債務(wù)。— Camille Fournier
但我們?nèi)匀恢档每紤] FaaS 是否會導(dǎo)致跟存儲過程類似的問題,包括 Camille 提到的技術(shù)債。有很多存儲過程給我們的教訓(xùn)可以放在 FaaS 場景下重新審視,存儲過程的問題在于:
通常依賴于服務(wù)商指定的語言,或者至少是指定的語言框架/擴(kuò)展
因?yàn)楸仨氃跀?shù)據(jù)庫環(huán)境中執(zhí)行所以很難測試
難以進(jìn)行版本控制,或者作為應(yīng)用包進(jìn)行管理
盡管不是所有存儲過程的實(shí)現(xiàn)都有這些問題,但它們都是常會碰到的。我們看看是否適用于 FaaS:
第一條就目前看來顯然不是 FaaS 的煩惱,直接排除。
第二條,因?yàn)?FaaS 函數(shù)都是純粹的代碼,所以應(yīng)該和其他任何代碼一樣容易測試。整合測試是另一個問題,我們稍后展開細(xì)說。
第三條,既然 FaaS 函數(shù)都是純粹的代碼,版本控制自然不成問題;最近大家開始關(guān)心的應(yīng)用打包,相關(guān)工具鏈也在日趨成熟,比如 Amazon 的 Serverless Application Model(SAM)和前面提到的其他 Serverless 框架都提供了類似的功能。2018 年初 Amazon 還開放了 Serverless Application Repository(SAR)服務(wù),方便組織分發(fā)應(yīng)用程序和組件,也是基于 AWS Serverless 服務(wù)構(gòu)建的。
福利
掃描添加小編微信,備注“姓名+公司職位”,加入【云計(jì)算學(xué)習(xí)交流群】,和志同道合的朋友們共同打卡學(xué)習(xí)!
推薦閱讀:
- 如何高效地準(zhǔn)備技術(shù)面試? 
- 漫畫:有趣的“帽子問題” 
- 我為什么放棄了 Chrome? 
- 5天破10億的哪吒,為啥這么火,Python來分析 
- 通俗易懂:圖解10大CNN網(wǎng)絡(luò)架構(gòu) 
- 互聯(lián)網(wǎng)公司上演反腐風(fēng)暴;GitHub CEO 對斷供表示無能為力;程序員面試錦集| 開發(fā)者周刊 
- 在其他國家被揭穿騙子又盯上非洲? 這幾個騙子公司可把非洲人民坑苦了…… 
總結(jié)
以上是生活随笔為你收集整理的被吹得天花乱坠的无服务器架构,究竟是什么?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 白话中台战略:中台是个什么鬼?
- 下一篇: boost::contract模块实现m
