無服務器架構(Serverless Architectures)(上)

譯註:html

  • 爲了便於對照參考,「Serverless」、「BaaS」 等術語文中不作翻譯。
  • 原文很長,這裏分紅上下兩篇。翻譯過程在 GitHub 上進行。

原文:https://martinfowler.com/articles/serverless.html
做者:Mike Roberts前端

無服務器架構(Serverless architectures)是指一個應用大量依賴第三方服務(後端即服務,Backend as a Service,簡稱「BaaS」),或者把代碼交由託管的、短生命週期的容器中執行(函數即服務,Function as a Service,簡稱「FaaS」)。如今最知名的 FaaS 平臺是 AWS Lambda。把這些技術和單頁應用等相關概念相結合,這樣的架構無需維護傳統應用中永遠保持在線的系統組件。Serverless 架構的長處是顯著減小運維成本、複雜度、以及項目起步時間,劣勢則在於更加依賴平臺供應商和現階段仍有待成熟的支持環境。git

引言

無服務器計算(Severless computing,簡稱 Serverless)如今是軟件架構圈中的熱門話題,三大雲計算供應商(Amazon、Google 和 Microsoft)都在大力投入這個領域,涌現了不可勝數的相關書籍、開源框架、商業產品、技術大會。到底什麼是 Serverless?它有什麼長處/短處?我但願經過本文對這些問題提供一些啓發。github

開篇咱們先來看看 Serverless 是什麼,以後我會盡我所能中立地談談它的優點和缺點。web

什麼是 Serverless

就像軟件行業中的不少趨勢同樣,Serverless 的界限並非特別清晰,尤爲是它還涵蓋了兩個互相有重疊的概念:docker

  • Serverless 最先用於描述那些大部分或者徹底依賴於第三方(雲端)應用或服務來管理服務器端邏輯和狀態的應用,這些應用一般是富客戶端應用(單頁應用或者移動端 App),創建在雲服務生態之上,包括數據庫(Parse、Firebase)、帳號系統(Auth0、AWS Cognito)等。這些服務最先被稱爲 「(Mobile) Backend as a Service」,下文將對此簡稱爲 「BaaS」。
  • Serverless 還能夠指這種狀況:應用的一部分服務端邏輯依然由開發者完成,可是和傳統架構不一樣,它運行在一個無狀態的計算容器中,由事件驅動、生命週期很短(甚至只有一次調用)、徹底由第三方管理(感謝 ThoughtWorks 在他們最近的「技術觀察」中對此所作的定義)。這種狀況稱爲 Functions as a service / FaaS。AWS Lambda 是目前的熱門 FaaS 實現之一,下文將對此簡稱爲 「FaaS」。

【邊欄註釋:「Serverless」 術語的起源】數據庫

本文將主要聚焦於 FaaS,不只僅由於它是 Serverless 中最新也最熱門的領域,更重要的是它和咱們傳統技術架構思路的顯著不一樣。後端

BaaS 和 FaaS 在運維層面有相似之處(都無需管理硬件資源),而且也常常配合使用。主流的雲服務商都會提供一套「Serverless 全家桶」,囊括了 BaaS 和 FaaS 產品——例如 Amazon 的 Serverless 產品介紹,Google 的 Firebase 服務也緊密集成了 Google Cloud Functions。api

對小公司而言這兩個領域也有交叉,Auth0 最初是一個 BaaS 產品,提供用戶管理的各類服務,他們後來建立了配套的 FaaS 服務 Webtask,而且將此概念進一步延伸推出了 Extend,支持其餘 BaaS 和 SaaS 公司可以輕鬆地在現有產品中加入 FaaS 能力。緩存

一些示例

界面驅動的應用(UI-driven applications)

咱們來設想一個傳統的三層 C/S 架構,例如一個常見的電子商務應用(好比在線寵物商店),假設它服務端用 Java,客戶端用 HTML/JavaScript:

在這個架構下客戶端一般沒什麼功能,系統中的大部分邏輯——身份驗證、頁面導航、搜索、交易——都在服務端實現。

把它改形成 Serverless 架構的話會是這樣:

這是張大幅簡化的架構圖,但仍是有至關多變化之處:

  1. 咱們移除了最初應用中的身份驗證邏輯,換用一個第三方的 BaaS 服務。
  2. 另外一個 BaaS 示例:咱們容許客戶端直接訪問一部分數據庫內容,這部分數據徹底由第三方託管(如 AWS Dynamo),這裏咱們會用一些安全配置來管理客戶端訪問相應數據的權限。
  3. 前面兩點已經隱含了很是重要的第三點:先前服務器端的部分邏輯已經轉移到了客戶端,如保持用戶 Session、理解應用的 UX 結構(作頁面導航)、獲取數據並渲染出用戶界面等等。客戶端實際上已經在逐步演變爲單頁應用
  4. 還有一些任務須要保留在服務器上,好比繁重的計算任務或者須要訪問大量數據的操做。這裏以「搜索」爲例,搜索功能能夠從持續運行的服務端中拆分出來,以 FaaS 的方式實現,從 API 網關(後文作詳細解釋)接收請求返回響應。這個服務器端函數能夠和客戶端同樣,從同一個數據庫讀取產品數據。
    咱們原始的服務器端是用 Java 寫的,而 AWS Lambda(假定咱們用的這家 FaaS 平臺)也支持 Java,那麼原先的搜索代碼略做修改就能實現這個搜索函數。
  5. 最後咱們還能夠把「購買」功能改寫爲另外一個 FaaS 函數,出於安全考慮它須要在服務器端,而非客戶端實現。它一樣經由 API 網關暴露給外部使用。

消息驅動的應用(Message-driven applications)

再舉一個後端數據處理服務的例子。假設你在作一個須要快速響應 UI 的用戶中心應用,同時你又想捕捉記錄全部的用戶行爲。設想一個在線廣告系統,當用戶點擊了廣告你須要馬上跳轉到廣告目標,同時你還須要記錄此次點擊以便向廣告客戶收費(這個例子並不是虛構,個人一位前同事最近就在作這項重構)。

傳統的架構會是這樣:「廣告服務器」同步響應用戶的點擊,同時發送一條消息給「點擊處理應用」,異步地更新數據庫(例如從客戶的帳戶里扣款)。

在 Serverless 架構下會是這樣:

這裏兩個架構的差別比咱們上一個例子要小不少。咱們把一個長期保持在內存中待命的任務替換爲託管在第三方平臺上以事件驅動的 FaaS 函數。注意這個第三方平臺提供了消息代理和 FaaS 執行環境,這兩個緊密相關的系統。

解構 「Function as a Service」

咱們已經提到屢次 FaaS 的概念,如今來挖掘下它到底是什麼含義。先來看看 Amazon 的 Lambda 產品簡介

經過 AWS Lambda,無需配置或管理服務器(1)便可運行代碼。您只需按消耗的計算時間付費 – 代碼未運行時不產生費用。藉助 Lambda,您幾乎能夠爲任何類型的應用程序或後端服務(2)運行代碼,並且所有無需管理。只需上傳您的代碼,Lambda 會處理運行(3)和擴展高可用性(4)代碼所需的一切工做。您能夠將您的代碼設置爲自動從其餘 AWS 服務(5)觸發,或者直接從任何 Web 或移動應用程序(6)調用。

  1. 本質上 FaaS 就是無需配置或管理你本身的服務器系統或者服務器應用便可運行後端代碼,其中第二項——服務器應用——是個關鍵因素,使其區別於現今其餘一些流行的架構趨勢如容器或者 PaaS(Platform as a Service)。

回顧前面點擊處理的例子,FaaS 替換掉了點擊處理服務器(可能跑在一臺物理服務器或者容器中,但絕對是一個獨立的應用程序),它不須要服務器,也沒有一個應用程序在持續運行。

  1. FaaS 不須要代碼基於特定的庫或框架,從語言或環境的層面來看 FaaS 就是一個普通的應用程序。例如 AWS Lambda 支持 JavaScript、Python 以及任意 JVM 語言(Java、Clojure、Scala 等),而且你的 FaaS 函數還能夠調用任何一塊兒部署的程序,也就是說實際上你能夠用任何能編譯爲 Unix 程序的語言(稍後咱們會講到 Apex)。FaaS 也有一些不容忽視的侷限,尤爲是牽涉到狀態和執行時長問題,這些咱們稍後詳談。

再次回顧一下點擊處理的例子——代碼遷移到 FaaS 惟一須要修改的是 main 方法(啓動)的部分,刪掉便可,也許還會有一些上層消息處理的代碼(實現消息監聽界面),不過這極可能只是方法簽名上的小改動。全部其餘代碼(好比那些訪問數據庫的)均可以原樣用在 FaaS 中。

  1. 既然咱們沒有服務器應用要執行,部署過程也和傳統的方式截然不同——把代碼上傳到 FaaS 平臺,平臺搞定全部其餘事情。具體而言咱們要作的就是上傳新版的代碼(zip 文件或者 jar 包)而後調用一個 API 來激活更新。
  2. 橫向擴展是徹底自動化、彈性十足、由 FaaS 平臺供應商管理的。若是你須要並行處理 100 個請求,不用作任何處理系統能夠天然而然地支持。FaaS 的「運算容器」會在運行時按需啓動執行函數,飛快地完成並結束。

回到咱們的點擊處理應用,假設某個好日子咱們的客戶點擊廣告的數量有平日的十倍之多,咱們的點擊處理應用能承載得住麼?咱們寫的代碼是否支持並行處理?支持的話,一個運行實例可以處理這麼多點擊量嗎?若是環境容許多進程執行咱們能自動支持或者手動配置支持嗎?以 FaaS 實現你的代碼須要一開始就以並行執行爲默認前提,但除此以外就沒有其餘要求了,平臺會完成全部的伸縮性需求。

  1. FaaS 中的函數一般都由平臺指定的一些事件觸發。在 AWS 上有 S3(文件)更新、時間(定時任務)、消息總線(Kinesis)消息等,你的函數須要指定監聽某個事件源。在點擊處理器的例子中咱們有個假設是已經採用了支持 FaaS 訂閱的消息代理,若是沒有的話這部分也須要一些代碼量。
  2. 大部分的 FaaS 平臺都支持 HTTP 請求觸發函數執行,一般都是以某種 API 網關的形式實現(如 AWS API GatewayWebtask)。咱們在寵物商店的例子中就以此來實現搜索和購買功能。

狀態

當牽涉到本地(機器或者運行實例)狀態時 FaaS 有個不能忽視的限制。簡單點說就是你須要接受這麼一個預設:函數調用中建立的全部中間狀態或環境狀態都不會影響以後的任何一次調用。這裏的狀態包括了內存數據和本地磁盤存儲數據。從部署的角度換句話說就是 FaaS 函數都是無狀態的(Stateless)

這對於應用架構有重大的影響,無獨有偶,「Twelve-Factor App」 的概念也有如出一轍的要求

在此限制下的作法有多種,一般這個 FaaS 函數要麼是自然無狀態的——純函數式地處理輸入而且輸出,要麼使用數據庫、跨應用緩存(如 Redis)或者網絡文件系統(如 S3)來保存須要進一步處理的數據。

執行時長

FaaS 函數能夠執行的時間一般都是受限的,目前 AWS Lambda 函數執行最長不能超過五分鐘,不然會被強行終止。

這意味着某些須要長時間執行的任務須要調整實現方法才能用於 FaaS 平臺,例如你可能須要把一個原先長時間執行的任務拆分紅多個協做的 FaaS 函數來執行。

啓動延遲

目前你的 FaaS 函數響應請求的時間會受到大量因素的影響,可能從 10 毫秒到 2 分鐘不等。這聽起來很糟糕,不過咱們來看看具體的狀況,以 AWS Lambda 爲例。

若是你的函數是 JavaScript 或者 Python 的,而且代碼量不是很大(千行之內),執行的消耗一般在 10 到 100 毫秒之內,大函數可能偶爾會稍高一些。

若是你的函數實如今 JVM 上,會偶爾碰到 10 秒以上的 JVM 啓動時間,不過這隻會在兩種狀況下發生:

  • 你的函數調用觸發比較稀少,兩次調用間隔超過 10 分鐘。
  • 流量突發峯值,好比一般每秒處理 10 個請求的任務在 10 秒內飆升到每秒 100 個。

前一種狀況能夠用個 hack 來解決:每五分鐘 ping 一次給函數保持熱身。

這些問題嚴重麼?這要看你的應用類型和流量特徵。我先前的團隊有一個 Java 的異步消息處理 Lambda 應用天天處理數億條消息,他們就徹底不擔憂啓動延遲的問題。若是你要寫的是一個低延時的交易程序,目前而言確定不會考慮 FaaS 架構,不管你是用什麼語言。

不論你是否定爲你的應用會受此影響,都應該以生產環境級別的負載測試下實際性能狀況。若是目前的狀況還不能接受的話,能夠幾個月後再看看,由於這也是如今的 FaaS 平臺供應商們主要集中精力在解決的問題。

API 網關

API Gateway

咱們前面還碰到過一個 FaaS 的概念:「API 網關」。API 網關是一個配置了路由的 HTTP 服務器,每一個路由對應一個 FaaS 函數,當 API 網關收到請求時它找到匹配請求的路由,調用相應的 FaaS 函數。一般 API 網關還會把請求參數轉換成 FaaS 函數的調用參數。最後 API 網關把 FaaS 函數執行的結果返回給請求來源。

AWS 有本身的一套 API 網關,其餘平臺也大同小異。

除了純粹的路由請求,API 網關還會負責身份認證、輸入參數校驗、響應代碼映射等,你可能已經敏銳地意識到這是否合理,若是你有這個考慮的話,咱們待會兒就談。

另外一個應用 API 網關加 FaaS 的場景是建立無服務器的 http 前端微服務,同時又具有了 FaaS 函數的伸縮性、管理便利等優點。

目前 API 網關的相關工具鏈還不成熟,儘管這是可行的但也要夠大膽才能用。

工具鏈

前面關於工具鏈還不成熟的說法是指大致上 FaaS 無服務器架構平臺的狀況,也有例外,Auth0 Webtask 就很重視改善開發者體驗,Tomasz Janczuk 在最近一屆的 Serverless Conf 上作了精彩的展現。

無服務器應用的監控和調試仍是有點棘手,咱們會在本文將來的更新中進一步探討這方面。

開源

無服務器 FaaS 的一個主要好處就是隻須要近乎透明的運行時啓動調度,因此這個領域不像 Docker 或者容器領域那麼依賴開源實現。將來確定會有一些流行的 FaaS / API 網關平臺實現能夠跑在私有服務器或者開發者工做站上,IBM 的 OpenWhisk 就是一個這樣的實現,不知道它是否能成爲流行選擇,接下來的時間裏確定會有更多競爭者出現。

除了運行時的平臺實現,仍是有很多開源工具用以輔助開發和部署的,例如 Serverless Framework 在 API 網關 + Lambda 的易用性上就比它的原創者 AWS 要好不少,這是一個 JS 爲主的項目,若是你在寫一個 JS 網關應用必定要去了解下。

再如 Apex——「輕鬆建立、部署及管理 AWS Lambda 函數」。Apex 有意思的一點是它容許你用 AWS 平臺並不直接支持的語言來實現 Lambda 函數,好比 Go。

什麼不是 Serverless

在前文中我定義了 「Serverless」 是兩個概念的組合:「Backend as a Service」 和 「Function as a Service」,而且對後者的特性作了詳細解釋。

在咱們開始探討它的好處和弊端以前,我想再花點兒時間在它的定義上,或者說:區分開那些容易和 Serverless 混淆的概念。我看到一些人(包括我本身最近)對此都有困惑,我想值得對此作個澄清。

對比 PaaS

既然 Serverless FaaS 這麼像 12-Factor 應用,那不就是另外一種形式的 Platform as a Service 麼?就像 Heroku?對此借用 Adrian Cockcroft 一句很是簡明的話:

若是你的 PaaS 能在 20ms 內啓動一個只運行半秒鐘的實例,它就叫 Serverless。
Adrian Cockcroft

換句話說,大部分 PaaS 應用不會爲了每一個請求都啓動並結束整個應用,而 FaaS 就是這麼作的。

好吧,然而假設我是個嫺熟的 12-Factor 應用開發者,寫代碼的方式仍是沒有區別對麼?沒錯,可是你如何運維是有很大不一樣的。鑑於咱們都是 DevOps 工程師咱們會在開發階段就充分考慮運維,對吧?

FaaS 和 PaaS 在運維方面的關鍵區別是伸縮性(Scaling)。對於大多數 PaaS 平臺而言你須要考慮如何伸縮,例如在 Heroku 上你要用到多少 Dyno 實例?對於 FaaS 應用這一步驟是徹底透明的。即使你將 PaaS 配置爲自動伸縮,也沒法精細到單個請求級別,除非你有一個很是明確穩定的流量曲線能夠針對性地配置。因此 FaaS 應用在成本方面要高效得多。

既然如此,何須還用 PaaS?有不少緣由,最主要的因素應該是工具鏈成熟度。另外像Cloud Foundry 可以給混合雲和私有云的開發提供一致體驗,在寫就本文的時候 FaaS 尚未這麼成熟的平臺。

對比容器

使用 Serverless FaaS 的好處之一是避免在操做系統層面管理應用程序進程。有一些 PaaS 平臺如 Heroku 也提供了這樣的特性;另外一種對進程的抽象是容器,這類技術的表明是 Docker。容器託管系統(Mesos、Kubernetes 等)把應用從系統級開發中抽象出來,這種作法日漸流行,甚至在此之上雲服務商的容器平臺(如 Amazon ECSEKSGoogle Cloud Engine)也像 Serverless FaaS 同樣容許團隊從管理主機中徹底解放出來。在這股容器大潮中,FaaS 是否還有優點?

概念上來講前面對 PaaS 的論斷仍舊適用於容器。Serverless FaaS 的伸縮性是徹底自動化、透明、良好組織的,而且自動進行資源監控和分配;而容器平臺仍舊須要你對容量和集羣進行管理。

另外我還得說容器技術也處在不夠成熟和穩定的階段,儘管它愈來愈接近了。固然這不是說 Serverless 就成熟了,但你終究須要在兩個都屬前沿的技術方向中作出選擇。

還有個值得一提的是很多容器平臺支持了自動伸縮的容器集羣,Kubernetes 有內建的 Horizontal Pod Autoscaling 功能,AWS Fargate 則承諾會有「Serverless 容器」。

總的來講 Serverless FaaS 和託管容器在管理和伸縮性方面的差異已經不大,在它們之間的取捨更多看風格取向和應用的類型。例如事件驅動的應用組件更適合用 FaaS 實現,而同步請求驅動的應用組件更適合用容器實現。我預計很快就會有很多團隊和應用同時採用這兩種架構模式,期待看它們會擦出怎樣的火花。

對比 NoOps

Serverless 並不是「零運維」——儘管它多是「無系統管理員」,也要看你在這個 Serverless 的兔子洞裏走多深。

「運維」的意義遠不止系統管理,它還包括並不限於監控、部署、安全、網絡、支持、生產環境調試以及系統伸縮。這些事務一樣存在於 Serverless 應用中,你仍舊須要相應的方法處理它們。某些狀況下 Serverless 的運維會更難一些,畢竟它仍是個嶄新的技術。

系統管理的工做仍然要作,你只是把它外包給了 Serverless 環境。這既不能說壞也不能說好——咱們外包了大量的內容,是好是壞要看具體狀況。不論怎樣,某些時候這層抽象也會發生問題,就會須要一個來自某個地方的人類系統管理員來支持你的工做了。

Charity Majors 在第一屆 Serverless 大會上就這個主題作了個很是不錯的演講,也能夠看看她相關的兩篇文章:WTF is operations?Operational Best Practices)。

對比存儲過程即服務

還有一種說法把 Serverless FaaS 看作「存儲過程即服務(Stored Procedures as a Service)」,我想緣由是不少 FaaS 函數示範都用數據庫訪問做爲例子。若是這就是它的主要用途,我想這個名字也不壞,但終究這只是 FaaS 的一種用例而已,這樣去考慮 FaaS 侷限了它的能力。

我好奇 Serverless 會不會最終變成相似存儲過程那樣的東西,開始是個好主意,而後迅速演變成大規模技術債務。
Camille Fournier

但咱們仍然值得考慮 FaaS 是否會致使跟存儲過程相似的問題,包括 Camille 提到的技術債。有不少存儲過程給咱們的教訓能夠放在 FaaS 場景下從新審視,存儲過程的問題在於:

  1. 一般依賴於服務商指定的語言,或者至少是指定的語言框架/擴展
  2. 由於必須在數據庫環境中執行因此很難測試
  3. 難以進行版本控制,或者做爲應用包進行管理

儘管不是全部存儲過程的實現都有這些問題,但它們都是常會碰到的。咱們看看是否適用於 FaaS:

第一條就目前看來顯然不是 FaaS 的煩惱,直接排除。

第二條,由於 FaaS 函數都是純粹的代碼,因此應該和其餘任何代碼同樣容易測試。整合測試是另外一個問題,咱們稍後展開細說。

第三條,既然 FaaS 函數都是純粹的代碼,版本控制天然不成問題;最近你們開始關心的應用打包,相關工具鏈也在日趨成熟,好比 Amazon 的 Serverless Application Model(SAM)和前面提到的其餘 Serverless 框架都提供了相似的功能。2018 年初 Amazon 還開放了 Serverless Application Repository(SAR)服務,方便組織分發應用程序和組件,也是基於 AWS Serverless 服務構建的。關於 SAR 能夠看看個人另外一篇文章:Examining the AWS Serverless Application Repository

本文翻譯的實時更新: https://amio.github.io/server...
相關文章
相關標籤/搜索