Serverless Architectures(譯文)(1)—(Martin Fowler)

原文地址:https://martinfowler.com/articles/serverless.html
作者:Martin Fowler, Mike Roberts

1. 摘要

  無服務器架構是一種應用程序設計方法,它合併了第三方“Backend as a Service”(BaaS)提供的服務,和/或運行在FaaS(Functions as a Service)平臺中的用戶代碼。使用這樣的思路並結合一些類似spa(單頁應用)的應用,設計出的架構消除了對傳統常駐服務器組件的大部分需求。無服務器架構將受益於顯著降低的操作成本、複雜性和工程領先時間,但也會因依賴於服務提供商和相對不成熟的支撐技術而增加成本。

2. 引言

  “Serverless computing”,或簡稱爲“Serverless”,是軟件架構世界中的一個熱點主題。三大雲廠商- Amazon, Google, and Microsoft都對無服務器架構進行了重點佈局。我們已經看到許多許多書籍、開源項目、會議和軟件廠商在致力於這個領域。但是什麼是無服務器架構,它是否值得研究?通過這篇文章中我希望能夠拋磚引玉。

3. 什麼是無服務器架構

  對於無服務器架構沒有一個清晰的視圖。對於初學者,它包含兩個不同但重疊的區域:

  1. Serverless最初用於描述那些完全包含第三方的、雲託管的、管理服務器端邏輯和狀態的應用和服務的應用程序。這些都是典型的“富客戶端”應用程序(考慮單頁的web應用程序,或者移動應用程序),它們使用可訪問雲數據庫的龐大生態系統(如Parse、Firebase)、身份驗證服務(例如Auth0、AWS Cognito)等等。這些類型的服務以前被描述爲““Backend as a Service”,在本文中,我使用“BaaS”作爲簡寫。
  2. 無服務器架構也意味着應用程序開發人員仍然需要編寫服務器端邏輯的應用程序,但是,與傳統的體系結構不同,它是在無狀態計算容器中運行的。這些容器是事件觸發的、臨時的(可能只持續一次調用就掛),並全管理由第三方完。有人也把其稱之爲“函數即服務”或“FaaS”。AWS Lambda是目前最流行的FaaS平臺之一,當然也有一些其它的實現平臺。
      在本文中,我們將主要關注FaaS。它不僅是一個更新和更着名氣的領域,而且它與我們常用的技術架構思想有很大的不同。
      BaaS和FaaS在它們的操作屬性上是相關的(如沒有資源管理),並且經常一起使用。大型雲供應商都有“無服務器架構的產品組合”,包括BaaS和FaaS產品(例如,here’s Amazon’s Serverless是亞馬遜的無服務器產品頁面。Google的Firebase BaaS數據庫通過使用Google Cloud Functions for Firebase提供顯式的FaaS支持)。
      更多的公司也開始涉足於這兩個領域。Auth0開始使用實現了許多用戶管理方面功能的BaaS產品,並隨後創建了配套的FaaS服務Webtask。現在該公司已經提供了 Extend,這使得其他SaaS和BaaS公司能夠輕鬆地將FaaS功能添加到現有產品中,以創建一個統一的無服務器架構產品。

    3.1. 兩個示例

    3.1.1. UI驅動的應用

      讓我們考慮一個傳統的三層面向客戶的系統,它具有服務器端邏輯。一個典型的電子商務應用就是很好的例子就是...我可以舉在線寵物商店的例子嗎?
      傳統架構將如下圖所示。如它在服務器端用Java或Javascript實現的,在客戶端使用HTML+Javascript實現:
    圖1
      使用這種體系結構,客戶端可能相對薄弱,系統中的許多邏輯功能如身份驗證、頁面導航、搜索、事務,都要由服務器應用程序實現。
      如果使用無服務器架構,看起來系統是這樣的:
    圖2
      儘管上圖是一個簡化後的視圖,但我們仍從其中看到許多變化:

    1. 我們看到原來應用中的鑑權邏輯已經被第三方的Baas服務所替代(如Auth0)。
    2. 使用另一個Baas服務,我們可以看到客戶端可以直接訪問我們一個數據庫子集(完全由第三方提供,例如Google Firebase)。相比於之前在服務端訪問數據庫資源,可以在客戶端通過實施不同的安全策略來訪問數據庫。
    3. 前面的兩點引導出了重要的第三點:在這個寵物店服務器端的一些應用邏輯已經轉移到了客戶端,如維護一個用戶會話,從數據庫中讀取數據並將其轉換爲可用的視圖。客戶端變成了一個SPA(單頁面應用)。
    4. 我們也希望在服務端保留一些與用戶體驗相關的功能,例如訪問大量的數據並做密集計算。在我們的寵物店商店中,這樣的一個功能可能是“查詢”。不像原來架構中需要一直在運行的服務器,可以實現一個響應經過API網關的HTTP請求的FaaS函數達到這一目的。客戶端和服務端的“查詢”功能都是從同一個產品數據庫中讀取數據。如果選擇AWS Lambda作爲FaaS平臺,可以將原來的查詢代碼原封不動地移植過來,因爲Lambda支持java和javascript語言。
    5. 最後,可以用另一個單獨的FaaS函數來替代我們的“購買”功能,出於安全考慮,選擇將它放在服務器端,而不是在客戶端重新實現它。它也依賴於一個API網關。在使用FaaS時,將不同的邏輯需求分解爲單獨部署的組件是一種非常常見的方法。
        退一步說,這個示例展示了另一個對無服務器架構而言非常重要的觀點:在傳統架構中,所有流、控制和安全性都由中央服務器應用程序管理,而在無服務器架構中,沒有處理這些的中央控制器。相反,我們傾向於通過對組件的編排完成目標(choreography over orchestration),將每個組件都設計爲更易被架構感知,這種設計思路在微服務方法中也很常見。
        這種設計方法有很多好處。正如Sam Newman在他的“Building Microservices" 這本書中指出的那樣:以這種方式構建的系統通常“更靈活,更易於改變”,既可以對於整體,也可以通過對組件進行系統的更新;具有更好的劃分關注點;還有一些令人着迷的成本效益,Gojko Adzic在這次精彩的演講中討論了這個問題。
        當然,這樣的設計也需要權衡:它需要更強大的分佈式監控,並且依賴於底層平臺安全能力。更重要的是,相比於單塊系統,在我們的頭腦中環繞着更多的靈活組件,而且增加多個後端組件的帶來的複雜性會讓我們考慮其所帶來的靈活性和降低成本是否值得。如何權衡需要依賴於具體應用上下文。

      3.1.2. 消息驅動的應用

        另一個例子是後端數據處理服務。
        假設您正在編寫一個以用戶爲中心的應用程序,它需要快速響應UI請求,其次,它需要捕獲正在發生的所有不同類型的用戶活動,以便進行後續處理。考慮這樣一個在線廣告系統:當用戶點擊一個廣告時,需要快速地將他們重定向到廣告目標。與此同時,你需要收集對這個廣告的點擊事件以便於向廣告客戶收費(這個例子是真實的,我以前在Intent Media裏的團隊有這樣的需求,他們以一種無服務器方式實現了這個需求)。
        使用傳統方法,體系結構可能如下圖所示。“Ad Server”同步響應用戶(未顯示在圖中),並將“click message”事件發送到一個消息通道。然後,這個消息由一個更新數據庫的“click processor”應用程序異步處理,例如,用來根據統計信息減少廣告客戶的預算。
      圖3
        如果使用無服務器架構,看起來是這樣的:
      圖4
        你能看出其中的區別嗎?與我們的第一個示例相比,這裏的體系結構的變化要小得多——這就是爲什麼異步消息處理對於無服務器技術來說非常流行的原因。我們用FaaS函數替換了一個常駐的消息消費者應用程序。這個函數在雲平臺供應商提供的事件驅動上下文中運行。請注意,雲平臺供應商應同時提供message broker和FaaS環境——這兩個是緊密聯繫的。
        FaaS環境也可以通過實例化函數代碼的多個副本來並行處理多條消息。這可能是我們遷移原來代碼時需要考慮的一個新問題。

      3.2. 解密FaaS

        我們已經提到了FaaS,現在是時候深入研究它真正的含義了。爲了做到這一點,我們來看看亞馬遜的FaaS產品Lambda的開頭描述。在這段描述中已經添加了一些標記。
      ...
        AWS Lambda允許您在沒有配置或管理服務器的情況下運行代碼。(1)…使用Lambda,您幾乎可以運行任何類型的應用程序或後端服務(2)這些程序都是零管理,只要上傳你的代碼,Lambda就會處理、運行(3)和縮放(4)你的代碼以實現高可用性。您可以設置您的代碼從其他AWS服務自動觸發(5),或者直接從任何web或移動應用程序調用(6)
      ...

      1. 從根本上說,FaaS運行後端代碼不需要考慮服務器系統或常駐應用程序的管理。如果回到之前的點擊處理示例,FaaS將取代點擊處理服務器(可能是一個物理機器,但肯定是一個特定的應用程序),它不需要一個指定的服務器,也不需要一個常駐的應用程序。
      2. FaaS產品不需要對特定的框架或庫進行編碼。當涉及到語言和環境時,FaaS函數是常規的應用程序。例如,AWS Lambda函數可以在Javascript、Python、Go、任何JVM語言(Java、Clojure、Scala等)或任何.NET語言中實現“first class”。然而,您的Lambda函數也可以執行與它的部署組件捆綁在一起的另一個進程,因此實際上可以使用任何能編譯成Unix進程的語言(參見Apex)。
        FaaS函數還是具有特定架構限制的,特別是在狀態和執行時間方面。我們很快就會講到。
        我們仍然考慮一下點擊處理示例。在遷移到FaaS時,惟一需要更改的代碼是“main方法”(啓動)代碼,它將被刪除。還有就是頂層消息處理程序(“消息偵聽器接口”實現)的特定代碼,但可能僅需要更改一下方法簽名。代碼的其餘部分(例如,寫入數據庫的代碼)在FaaS世界中沒有什麼不同。
      3. 部署方式與傳統系統非常不同,因爲不需要使用服務器應用程序來運行。在FaaS環境中,將函數代碼上載到FaaS提供商,提供商則負責提供所有需要的資源、實例化vm、管理流程等其他一切必要的內容。
      4. 水平擴展是完全自動的、有彈性的,並且由提供商管理。如果您的系統需要並行處理100個請求,那麼平臺會自動處理這種伸縮性。執行函數的“計算容器”是暫態的,FaaS何時創建和銷燬它們純粹由運行時需求驅動。最重要的是,使用FaaS,提供商處理所有底層資源供應和分配——用戶根本不需要集羣或VM管理。
        讓我們回到點擊處理器。比如說我們今天的點擊率不錯,顧客們點擊的廣告數量是平時的十倍。對於傳統的架構,我們的點擊處理應用程序能夠處理這個問題嗎?例如,我們是否開發了能夠一次處理多個消息的應用程序?如果我們這樣做了,應用程序的一個運行實例是否足以處理這樣的負載?如果運行多個進程,自動伸縮配置需要手動配置嗎?有了FaaS,所有這些問題都已經得到了回答,當然所編寫函數需要適配並行伸縮機制, FaaS實現自動處理所有伸縮需求的機制。
      5. FaaS中的函數通常由提供商定義的事件類型觸發。Amazon AWS中的觸發方式包括S3(文件/對象)更新、時間(預定任務)和添加到消息總線的消息(例如,Kinesis)。
      6. 大多數提供商還允許函數作爲入站HTTP請求的響應觸發函數;在AWS中,通常通過使用API網關來實現這個功能。在前面的寵物商店示例中,使用了一個API網關來進行“搜索”和“購買”功能。函數還可以通過平臺提供的API直接調用,但這是一種相對少見的用法。

        3.2.1. 狀態

          當涉及到本地(機器/綁定實例)狀態時,FaaS函數有很大限制。如存儲在內存變量的數據,或者寫入本地磁盤的數據。不能保證這種狀態數據會在多個調用中保持,而且更重要的是,不能假定一次函數調用的狀態可用於同一函數的另一次調用。因此,FaaS函數通常被描述爲無狀態的,更準確地說,任何需要持久的FaaS函數狀態都需要在FaaS函數實例之外實施。
          對於FaaS函數來說,它們是天然無狀態的,如對那些提供對輸入進行純功能轉換輸出的應用。但對另一些應用來說,這可能會對應用程序架構產生很大影響,儘管不是唯一的——“Twelve-Factor app”概念也有完全相同的限制。這種面向狀態的函數通常會使用數據庫、跨應用的緩存(如Redis)、或網絡文件/對象倉庫(如S3)用於在請求之間存儲狀態,或者提供處理請求所需的更多輸入。

        3.2.2. 執行時間

          FaaS函數通常對每次調用允許運行的時間有限制。目前,AWS Lambda函數對事件響應的“超時”最多爲5分鐘,然後會終止。微軟Azure和Google雲功能也有類似的限制。
          這意味着FaaS函數不適合某類長時間運行任務。因而需要重新設計架構——可能需要創建幾個不同的協同FaaS函數,而在傳統環境中,可能有一個常駐運行任務進行協調和執行。

        3.2.3. 啓動延遲和“冷啓動”

          一個FaaS平臺需要一些時間在處理每個事件之前初始化一個函數實例。這種啓動延遲對於一個特定的功能可能會有很大的不同,根據不同上下文,可能在幾毫秒到幾秒之間。這聽起來的確糟糕,但是讓我們花點時間研究一下AWS Lambda的例子。
          Lambda函數的初始化是一個“熱啓動”過程,也是一個“冷啓動”過程:重用一個處理先前事件的Lambda函數實例及其宿主容器是一個“熱啓動”過程;創建一個新的容器實例、啓動一個函數宿主進程是一個“冷啓動”過程。很明顯,啓動延遲主要是這些“冷啓動”所帶來的。
          冷啓動延遲依賴於許多因素:使用的語言;使用的庫;代碼數量;使用的Lambda函數環境變量;是否需要連接VPC資源等等。但這些因素中的大部分都是開發者可控的,因此通常可以優化這些因素以降低啓動延遲。
          與冷啓動時間同樣重要的是冷啓動頻率。例如,如果一個函數每秒處理10個事件,每個事件的處理時間爲50ms,你將會看到一次冷啓動可處理100,000–200,000個事件。但如果一個事件需要一個小時來處理,你將會看到每次處理一個事件都需要一次冷啓動,因爲Amazon的每個Lambda函數實例只持續數分鐘。瞭解這些可以幫助你瞭解冷啓動是否會產生影響,以及是否想要執行“保留”函數實例,以避免它們被釋放。
          是否需要關注冷啓動帶來的影響依賴於應用程序應用形態與業務類型。我的一個Intent Media團隊使用JAVA實現了一個異步消息處理Lambda app,這個app每天處理上億的消息,但是團隊並不關心這個組件的啓動延遲。也就是說,如果你正在編寫一個低延遲的交易應用程序,可能不希望在這個時候使用FaaS平臺。
          不管你是否認爲你的應用程序是否存在這樣的問題,都應該使用類似於生產環境的負載來測試性能。如果用例現在不起作用,可在幾個月內再次嘗試,這也是FaaS供應商不斷改進的主要領域。
          關於冷啓動的更多細節,可參考我的另一篇文章

        3.2.4. API網關

        圖5
          我們之前對無服務器架構關注的一個方面是“API網關”。一個API網關是一個HTTP服務器,其中路由和端點是在配置中定義的,並且每條路由都與一個資源相關聯,以處理該路由。在無服務器架構中,這樣的處理程序通常是FaaS函數。
          當一個API網關接收到一個請求時,它會找到匹配請求的路由配置,並且,在一個由 FaaS-backed支持的路由的情況下,將調用相關的FaaS函數以響應原始請求。通常,API網關將允許從HTTP請求參數映射到FaaS函數中的輸入參數,或者允許整個HTTP請求通過(通常作爲一個JSON對象)。FaaS功能將執行它的邏輯,並將結果返回給API網關,後者又將這個結果轉換爲HTTP響應,並將其傳回給原始調用者。
          Amazon Web Services有自己的API網關(稍微有點混亂地命名爲“API網關”),其他供應商也提供類似的功能。Amazon的API網關是一個BaaS(是的,BaaS!)服務,是一個配置的獨立外部服務,但你自己不需要提供和運行它。
          除了純粹的路由請求之外,API網關還可以執行身份驗證、輸入驗證、響應碼映射等等。(如果你認爲這真的是一個好主意,你的感覺會刺痛你的想法!我們稍後再考慮這個問題。)
          帶有FaaS功能的API網關的一個用例是:以一種無服務器的方式創建基於http的前端微服務,進行FaaS函數的擴展、管理和其它功能。
          當我第一次寫這篇文章的時候,Amazon API網關的工具,還是非常不成熟的。但現在這些工具已經有了很大改進。像AWS API網關這樣的組件並不是很“主流”,但希望它們會繼續改進。

        3.2.5. 使用工具

          上面關於工具成熟度的評論也適用於無服務器的FaaS。在2016年,情況相當糟糕;到2018年,我們已經看到了顯著的改善,我們預計工具將會變得更好。
          在FaaS世界中,有幾個值得注意的“開發者用戶體驗”的例子值得一看。首先是Auth0 Webtask,它在工具中將開發者用戶體驗放置了極高的優先級。其次是微軟的Azure函數產品,微軟一直將Visual Studio的緊密反饋循環放在其開發產品的首位,而Azure函數也不例外。考慮到來自雲觸發事件的輸入,Azure函數提供了本地調試功能的能力,這是非常特別的。
          一個仍然需要顯著改善的領域是監控。

        3.2.6. 開源

          到目前爲止,我主要討論的是商用提供商的產品和工具。大多數無服務器應用程序都使用了這些服務,但還是存在一些開源項目的。
          在無服務器中,開源最常見的一般是FaaS工具和框架,尤其是流行的 Serverless Framework,它的目標是使使用AWS API網關和Lambda變得比使用AWS提供的工具更容易。它還提供了大量的跨提供商工具抽象,一些用戶認爲這是有價值的。類似工具的例子包括Claudia和Zappa。另一個例子是Apex,這一點特別有趣,因爲它允許你使用除Amazon直接支持的語言之外的語言開發Lambda函數。
          不過,在開源工具派對上,大廠商自己也不會落後。AWS自己的部署工具SAM(Serverless Application Model)也是開源的。
          專用FaaS的主要好處之一是不必擔心底層的計算基礎設施(機器、vm、甚至容器)。但是如果你想要關心這些事情呢?也許你有一些雲供應商不能滿足的安全需求,或者已經購買了一些並不想丟棄的服務器機架。在這些場景中,開源軟件能夠幫助你運行自己的“服務器化”的FaaS平臺嗎?
          是的,已經有大量這方面的案例了。在開源FaaS方面的領導者是IBM(它的OpenWhisk項目已經成爲一個Apache項目)。微軟在這方面的產品是 Azure Functions 平臺。許多其他自託管FaaS實現都使用了底層容器平臺(如Kubernetes)。在這個領域,我們有必要研究一下像Galactic Fog, Fission和 OpenFaaS這樣的項目。這是一個技術飛速發展的時代,我建議可以看看雲計算聯盟(CNCF)Serverless Working Group 所做的工作。

        3.3. 什麼不是無服務器架構

          在這篇文章中,我將無服務器架構描述爲兩個概念的結合:BaaS和FaaS。並且詳細討論了後者。爲了更精確地瞭解我所認爲的無服務器技術關鍵屬性(以及爲什麼我認爲即使像S3這樣的老牌服務也屬於無服務器架構),我推銷一下我的另一篇文章:Defining Serverless
          在開始關注無服務器架構的優缺點之前,我想再花一點時間來定義一下什麼不是無服務器架構。

        3.3.1. 與PaaS比較

          考慮到無服務器的FaaS函數非常類似於 Twelve-Factor 應用, 它們只是像Heroku這樣的PaaS的另一種形式嗎?我引用 Adrian Cockcroft的一段話來回答這個問題。

        If your PaaS can efficiently start instances in 20ms that run for half a second, then call it serverless. -- Adrian Cockcroft

          換句話說,大多數PaaS應用程序不會爲了響應一個事件而波及整個應用,而FaaS平臺卻是這樣的。
          如果我是一個優秀的Twelve-Factor應用程序開發人員,雖說並不一定會影響我對應用程序的編寫與架構設計工作,但在操作方式上會產生很大影響。因爲我們都是深受DevOps影響的工程師,我們對運營考慮得與開發一樣多,對吧?
          FaaS和PaaS之間的關鍵操作差異是應用的伸縮性。一般而言,使用PaaS,仍然需要考慮如何擴展(例如Heroku,你要考慮運行多少個Dynos?),有了FaaS應用程序後這些工作完全透明。即使我們將PaaS應用程序設置爲自動伸縮,也無法對單個請求級別進行這樣的操作(除非有一個非常具體的流量配置文件),因此,當涉及運維成本時,FaaS應用程序的效率要高得多。
          考慮到這個優點,爲什麼還要使用PaaS呢?原因有很多,但最大的影響因素是工具。仍然有人在使用像Cloud Foundry這樣的PaaS平臺,能夠在混合雲上提供相同的開發體驗;但直到現在,還沒有一個類似功能的成熟FaaS出現。

        3.3.2. 與容器比較

          使用無服務器架構FaaS的一個原因是爲了避免在操作系統級管理應用程序進程。如Heroku這樣的PaaS服務也提供了這種功能。容器是現在流行的一種抽象技術,Docker是這種技術的代表。Mesos和Kubernetes這樣的容器管理系統,從操作系統級部署中抽象出單個應用程序,越來越受歡迎。在這條道路上,我們可以看到像Amazon ECS和EKS這樣的雲託管容器平臺,以及Google Container Engine,它們就像無服務器FaaS一樣,讓團隊不用再去管理自己的服務器主機。容器技術的發展推動了無服務器FaaS。
          我覺得PaaS與FaaS的區別仍然與容器有關:對於無服務器FaaS擴展是自動管理的、透明的、細粒度的,這與我前面提到的自動資源配置和分配有關。而傳統的容器平臺仍然需要事先配置好所管理集羣的大小和形態。
          我認爲目前容器技術仍然不成熟和穩定,儘管它正變得越來越好。
          當然,現在容器平臺中也可以實現自動伸縮功能,如Kubernetes的"Horizontal Pod Autoscaling"特性,而 AWS Fargate也推出了“無服務容器”。
          正如我們所看到的,在無服務器FaaS和容器託管兩者之間,管理和擴展特性之間的差距縮小了,如何選型最後僅僅歸結爲應用風格和應用類型的問題:如FaaS可能被認爲是構建擁有不同事件類型的事件驅動組件的更好選擇,而容器被看作是構建擁有多個入口點、同步請求驅動組件的更好選擇。
          我期望在相當短的一段時間內,更多應用程序和團隊將同時使用這兩種架構方法,並且看到這種應用模式的出現將是令人着迷的。

        3.3.3. 免維護(NoOps)

          無服務器架構並不意味着“沒有操作系統”。
          “Ops”的含義不僅僅包括服務器管理。它還意味着監控、部署、安全、網絡、支持,以及日常的一些生產調試和系統擴展。這些問題仍然存在於無服務器架構應用中,仍然需要使用策略來處理。在無服務器架構應用中進行運維在某些方面甚至更困難。
          無服務器架構的應用中仍然存在系統管理員,只不過對於開發者而言變得不可見,相當於開發者將對系統的管理外包給了無服務器架構的提供商。

        3.3.4. 存儲過程作爲服務

          我看到其它一些觀點:無服務器FaaS是“存儲過程即服務”。這是因爲許多FaaS函數的例子(包括我在本文中使用的一些函數)的確都是與數據庫緊密集成的小段代碼。如果這就是我們所能使用的FaaS全部,則這個名字是準確的,但實際上這些只是FaaS能力的一個子集。
          考慮一下存儲過程帶來的問題:

        1. 通常需要軟件提供商定義的特定語言,或在指定框架上對某一個語言的擴展。
        2. 因爲存儲過程的執行依賴於數據庫的上下文,因此非常難以測試。
        3. 版本控制很麻煩。
            讓我們看看這些特點是否也在FaaS上出現:
            問題1不會在FaaS中出現,所以我們可以馬上把它從列表中刪除。對於問題2,因爲我們處理的僅僅是代碼,所以單元測試肯定和其他代碼一樣簡單,集成測試問題稍後會討論。對於問題3,由於FaaS函數只是代碼,因此版本控制沒有問題,而且相關工具也不斷成熟,如Amazon的 Serverless Application Model(SAM)和前面提到的無服務器框架。在2018年初,亞馬遜甚至推出了一個“Serverless Application Repository”(SAR),爲組織提供了一種分發應用和應用組件,構建AWS Serverless 服務。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章