理解 Serverless:構建全服務應用程序的技巧和資源

本文要點

  • Serverless 不僅僅是功能即服務(FaaS)。
  • 不要擔心供應商鎖定;接受供應商通過事件集成來提供的功能。
  • 開源工具有助於簡化複雜應用程序的構建。
  • 使用基礎設施即代碼(Infrastructure as Code,IaC)的解決方案(如 CloudFormation)來定義 Serverless 應用程序並簡化 DevOps。
  • 強大的監控解決方案可以通過精確的成本管理和評估工具提供函數和集成性能的可視化。

儘管在過去幾年中, Serverless 技術已經得到了迅速普及,但是對於 Serverless 解決方案仍然存在許多誤解和擔憂。供應商鎖定、工具、成本管理、冷啟動、監控和開發生命週期都是 Serverless 技術相關的熱門話題。本文旨在解決其中的一些問題,並分享相關的技巧和資源,以指導 Serverless 新手構建功能強大、靈活且經濟高效的 Serverless 應用程序。

對 Serverless 技術的誤解

其中一個主要的誤解是,Serverless 等同於 功能即服務

Functions as a Service ,FaaS),因此不值得為此作出特別激進的改變。雖然 AWS Lambda 無疑是 Serverless 崛起的明星之一,並且可以說是 Serverless 架構越來越受歡迎的因素之一,但與 FaaS 相比,Serverless 還有更多功能。

Serverless 的核心原則是:我們不必擔心如何管理基礎設施或者擴容縮容,只需為使用的內容付費既可。如果考慮這些因素,那麼就有許多可用的服務了,比如 AWS DynamoDB、S3、SNS 或 SQS、Graphcooll、Auth0、Now、Netlify 或 Firebase(還有很多很多)。最終,Serverless 提供了強大的雲計算功能,而無需承擔管理基礎設施或優化容量可伸縮性的負擔和責任。這種抽象還意味著基礎設施層的安全不再是我們需要關心的問題了,考慮到維護安全標準的難度和複雜性,這是一個非常大的利好。最後但也很重要的是,如果我們不使用它所提供的基礎設施,那麼就不必為此付費。

也可以認為 Serverless 是一種“思想狀態”——一個人在設計解決方案時所採用的思維方式。避免使用需要維護任何基礎設施的方式。通過 Serverless 的方式,我們正在試圖將我們投入在項目中的工作時間重新分配到對用戶有更直接影響和益處的事情上,比如健壯的業務邏輯、能吸引用戶的界面及快速響應、可靠的 API 上。例如,如果我們可以通過支付 Algolia

來避免管理和維護一個自由文本搜索平臺,那麼這就是我們將要做的。以 Serverless 的方式來構建應用程序可以極大地縮短上市時間,因為我們不再需要擔心如何管理複雜的基礎設施了。這樣可以規避管理基礎設施產生的責任和成本,並能集中精力構建客戶真正需要的應用程序和服務,這種方式,Patrick Debois 稱之為“ 全服務 ”,這個術語已經得到了 Serverless 社區的認可。其次,函數應該被視為將服務綁定在一起的粘合劑,並且可概念化為部署單元(而不是部署整個庫或 Web 應用程序),從而允許對應用程序的部署和變更進行非常細粒度的控制。如果不能以這種方式部署函數,那麼這可能是一種代碼壞味道,表明該函數承擔了太多的職責,應該進行重構了。

在開發雲應用程序時,有些人擔心供應商鎖定。對於 Serverless,這種擔心仍然存在,我認為這是源於對 Serverless 真正含義的誤解。例如,以我在 AWS 上構建 Serverless 應用程序的經驗來看,採用 AWS Lambda 將其他 AWS 服務粘合在一起,是 Serverless 架構強大功能的一部分。這個例子很好地說明了整體是優於局部的。試圖避免供應商鎖定實際上會導致比我們想要解決的問題還要更嚴重的問題。使用容器時,在雲供應商之間管理自己的抽象層可能會更容易些,但是當使用 Serverless 時,特別是考慮到 Serverless 的成本效益時,這種努力就不值得了。一定要考慮供應商是如何提供設施來暴露服務的;一些專用服務依賴於與其他供應商的強大集成點,並且提供了開箱即用的鉤子。從 API 網關端點處指定需要調用的 Lambda 比將請求代理到現有容器或 EC2 實例中要更容易些。Graphcool 使用 Auth0 提供了簡單的配置,這比使用自定義標識提供程序也更容易。

為我們的 Serverless 應用程序選擇合適的供應商是一個架構決策問題。我們不應該假定某天再回過頭來管理服務器,並以此前提來構建 Serverless 應用程序。選擇雲供應商與選擇使用什麼容器或什麼數據庫來構建應用程序,甚至與用什麼語言來編寫代碼沒有什麼不同。

最好考慮下如下幾點:

  • 你需要什麼服務以及為什麼需要這些服務。
  • 雲服務供應商提供了哪些不同的服務,以及如何使用你所選擇的 FAAS 實現將這些服務粘合在一起。
  • 支持哪些編程語言(是動態類型還是靜態類型、是編譯代碼還是解釋代碼、基準測試、冷啟動性能、開源生態系統等)。
  • 你的安全要求是什麼(SLAS、2FA、OAuth、HTTPS、SSL 等)。
  • 如何管理 CI/CD 和軟件開發週期。
  • 可以利用什麼樣的基礎設施即代碼(IaC)解決方案。

如果你正在對一個現有的應用程序進行擴展並添加了 Serverless 功能,那麼這可能會限制你的選擇,不過幾乎所有 Serverless 技術都提供了某種形式的 API(通過 REST 端點或消息隊列),這些 API 提供了一個簡單的集成點來將應用程序擴展成可以獨立開發的核心應用程序。選擇使用那些提供了易理解的 API 並且具有可靠的文檔和強大社區的服務,這樣你就不會出錯了。很多時候,當談到 Serverless 技術時,集成的簡單性可能是我們關注的關鍵指標,它可能也是自 2015 年 Lambda 發佈以來,AWS 獲得成功的最大貢獻因素之一。

在什麼情況下使用 serverless 是有益的

Serverless 幾乎可以用在任何地方,我發現現在的使用情況還遠遠沒有發揮出 Serverless 計算的好處。由於 Serverless 技術的存在,雲計算的進入門檻現在非常低。如果開發人員有一個想法,但不知道如何管理雲基礎設施和優化成本,他們完全無需擔心是否能找到一個有工程背景的人來幫助他們。如果一家初創公司正在試圖構建一個平臺,但又擔心由此產生的成本,那麼他們可以採用 Serverless 的方式輕鬆實現。

由於 Serverless 能節約成本且具有可伸縮性,它可以像適用於具有遍佈全球數百萬用戶的 Web 應用程序那樣,適用於內部 IT 系統。當談到計費時,我們可以用美分而不是用歐元(或其他貨幣)來結算。這是非常強大的。就算是最基礎的 AWS EC2 實例(t1.micro)持續開一個月,即使什麼都不做(誰還沒有忘記關閉的時候呢!),我們也需要花費 15 歐元。為了和 AWS EC2 進行比較,產生相同的成本水平,我們需要在同一時間段內運行一個 1 秒內可達到 300 萬次的 512MB 的 Lambda 函數。同樣地,如果你不使用這個函數,它就不會產生任何費用。

由於 Serverless 主要是基於事件的,所以可以將 Serverless 基礎設施直接添加到傳統系統中。例如,可以使用 AWS S3、Lambda 和 Kinesis 為傳統零售系統搭建可以通過 API 網關端點接收數據的分析服務,或者使用 DynamoDB 流和 Algolia 來改進自由文本搜索系統。

絕大多數的 Serverless 平臺都支持多種語言,最常用的有 Python、JavaScript、 C#、Java 和 GO。一般來說,各語言都沒有對可使用的庫進行限制,因此,我們可以隨意選擇使用我們最擅長的開源代碼庫。然而,保持低依賴性仍是個不錯的主意,它可以確保函數儘可能地在最佳狀態下執行,並能利用 Serverless 應用程序強大的可伸縮性。容器需要裝載的包越多,冷啟動時間就越長。

冷啟動是指容器、運行時和函數處理程序在使用之前要先初始化。它可能會導致大約 3 秒的功能延遲,當你試圖為缺乏耐心的用戶提供響應時,這並不理想。不過,冷啟動只發生在函數空閒了幾分鐘後的第一次調用時。許多人認為這是個小麻煩,可以不斷檢測該函數保持其活躍,或者乾脆無視它。

雖然 AWS 已經發布了一個無服務器的 SQL 數據庫 Serverless Aurora ,但是,SQL 數據庫並不是一個理想的 Serverless 計算用例,因為它們是依賴連接來執行事務的,當 AWS Lambda 接收的吞吐量升高時,這些事務可能很快就會成為瓶頸。值得一提地是,雖然 Serverless Aurora 在不斷改進,但是目前像 DynamoDB 這樣的 NoSQL 解決方案才是更適用於 Serverless 計算的解決方案。不過,毫無疑問,這種情況在未來幾個月將會發生變化。

Serverless 能使用的工具也有一些限制,特別是用於本地測試方面的工具。雖然存在 docker-lambda、DynamoDB Local 和 lLocalStack 等解決方案,但通常它們非常複雜,需要大量配置。不過,所有這些項目都在積極的開發中,這些工具達到我們都能接受的標準只是時間問題。

Serverless 對開發生命週期的影響

由於我們的基礎設施始終都只是配置,所以可以使用腳本來指定和部署代碼。它既可以是簡單的 shell 腳本,也可以是諸如 AWS CloudFormation 之類的配置即代碼的解決方案。我偏向使用 CloudFormation 的原因是:雖然它沒有為每個區域都提供配置,但它能允許我們指定自定義的資源,並且這些自定義資源可以是簡單的 Lambda 函數。這意味著,當 CloudFormation 不能滿足我們的需求時,我們可以編寫一個自定義資源(一個 Lambda 函數)來彌補這個不足。我們可以使用支持 Lambda 的自定義資源來做任何事情,甚至可以在 AWS 環境之外配置依賴項。

同樣地,由於一切都是簡單的配置,因此可以根據環境 / 區域 / 用戶對部署腳本進行參數化,特別是當我們使用基礎設施即代碼(Infrastructure as Code ,IaC)解決方案(比如 CloudFormation)時。例如,我們可以為代碼倉庫中的每個分支部署基礎設施的副本,以便在開發期間對它們進行完全隔離的測試,這可以極大地減少開發人員的反饋循環測試,開發人員通過反饋循環測試來判斷其代碼在線上環境中是否能夠充分執行。管理者也無需擔心部署這麼多環境的成本問題,因為它們是按使用次數計費的。

DevOps 也不必擔心那麼多了,因為他們只需要確保開發人員的配置是正確的即可。他們不再需要管理實例、負載均衡或安全組了。當談到 Serverless,“NoOps”這個術語經常被提及,但是,擁有基礎設施配置方面的專業知識仍然是很重要的,尤其是擁有 IAM 配置和優化雲資源方面的知識。

一些非常強大的可視化監控工具(如 Epsagon、Thundra、Dashbird 和 IOPipe)可以提供可視化跟蹤 Serverless 應用程序的能力。它們可以提供諸如日誌記錄、跟蹤、函數性能度量、架構瓶頸、成本分析和評估等信息。這不僅能為 DevOps 工程師、開發人員和架構師提供深入瞭解應用程序執行情況的能力,還能夠幫忙管理層更好地瞭解實時的、秒級的資源成本和計費預測。如果使用託管的基礎設施,這些是很難做到的。

由於不再需要考慮 Web 服務器、虛擬機或容器管理、服務器補丁、操作系統、Internet 網關、跳箱等因素,架構 Serverless 應用程序變得簡單多了。不同職責的抽象使 Serverless 架構能夠更專注於最重要的事情,即滿足業務方和客戶的需求。

雖然相關工具現在還不夠完善(它們每天都在改進中),但是開發人員的體驗已經非常好了,因為開發人員不僅能更專注於編寫業務邏輯,也能以最好的方式將應用程序的複雜性轉移到架構中的不同服務上去。Serverless 應用程序的編排是基於事件並由雲供應商(如 SQS、S3 事件或 DynamoDB 流)抽象得出的,因此,開發人員需要做的僅僅是指定其業務邏輯將如何響應對應的事件,而無需擔心以怎麼的方式實現數據庫、消息隊列是最好的,或者在特定存儲設備上應該怎麼儘可能地優化操作數據等問題。

代碼可以像使用任何其他應用程序開發過程一樣在本地運行和調試。單元測試也沒有改變。正如我前面提到的,使用可定製的堆棧配置來部署整個應用程序基礎設施的能力,能夠使開發人員快速獲取關鍵的反饋信息,從而無需擔心測試成本或在昂貴的託管環境中運行的影響。

用於構建 Serverless 應用程序的工具和技術

現在還沒有構建 Serverless 應用程序的標準方式,用於構建 Serverless 的服務也是如此。在提供強大的 Serverless 解決方案方面,AWS 顯然是一個領導者,但是, 谷歌雲ZeitFirebase 也都值得一試。如果你正在使用 AWS,我推薦的方式是使用 無服務器應用程序模型 (Serverless Application Model,SAM)來構建應用程序,特別是使用 C#時,因為 Visual Studio 中的工具非常出色。Visual Studio 能做的任何事情,SAM CLI 也都能做到,因此,即使使用了不同的 IDE 或文本編輯器,也不必擔心會錯過任何東西。當然,SAM 也可以和其他語言一起使用。

當談到和其他語言一起使用時,Serverless Framework 是一個優秀的開源工具,它能夠使用非常強大的 YAML 配置文件來配置所有的內容。Serverless Framework 還能支持多雲供應商,因此,如果我們正在尋找一個多雲的解決方案,這個框架肯定能使我們的工作變得更輕鬆。它還有一個龐大的社區,社區裡有很多插件,基本可以滿足我們的需求。我曾經也為該社區做出過貢獻,社區的團隊成員都非常友好、樂於助人、熱情好客。

對於本地測試,docker-lambda、Serverless Local、DynamoDB Local 和 LocalStack 都是很好的開源工具。但 Serverless 工具目前還處於初級階段,因此,如果我們的場景比較複雜,通常需要做一些額外的工作才能使本地測試正常運行。然而,簡單地將堆棧部署到我們的環境中並進行測試是非常便宜的。這樣做的好處是不必擔心在本地是否精確複製了雲環境。

使用 AWS Lambda 層可以減小部署包,並能縮短加載時間。

確保我們使用了正確的編程語言。不同的語言有不同的優缺點。目前有很多基準測試,但當談到 AWS Lambda 性能時,JavaScript、Python 和 C#(.NET Core 2.1+)明顯是領先者。最近,AWS Lambda 引入了運行時 API,該 API 允許我們指定我們想要使用的語言和運行時,因此可以隨意嘗試了(C++、其他任何語言?)。

需要一直保持較小的部署包。部署包越小加載就越快。避免引入大型庫,特別是當我們只使用大型庫中的一兩個功能時。如果我們正在使用 JavaScript 編程,請確保使用 Webpack 之類的構建工具來優化我們的構建,並且只引入我們所需要的內容。雖然 .NET Core 3.0 引入了 QuickJIT 和有助於提高性能的分層編譯,但它對冷啟動有很大的幫助。

Serverless 函數基於事件的特性可能會使業務邏輯在開始時難以協調。在這方面,消息隊列和狀態機是非常有用的。Lambda 函數可以相互調用,但也只在不需要等待響應(觸發即忘記)的情況下才能這樣做——我們也不希望在等待另一個函數完成後才計費。在分離業務邏輯領域、控制應用程序瓶頸和處理事務(使用 FIFO 隊列時)時,消息隊列非常有用。可以將 AWS lambda 函數作為死信隊列分配給 SQS 隊列,來跟蹤失敗事件以進行分析。當需要將函數連接在一起管理複雜的過程時,AWS 步驟函數(AWS Step Functions,狀態機)非常有用。步驟函數不需要讓 Lambda 函數調用另一個函數,也可以協調狀態轉換、在函數之間傳遞數據,並能管理全局函數狀態。它還允許指定重試條件,或者在發生特定錯誤時執行特定操作,功能是非常強大的。

結論

過去幾年中,Serverless 的發展速度十分驚人。對於這種範式的轉換存在一些誤解。從簡化開發和 DevOps 到由於抽象的基礎設施和可伸縮的管理而大大降低了運營成本,Serverless 解決方案在整個開發生命週期中都有很大的優勢。儘管 Serverless 也有其侷限性,但是有一些可靠的技術和設計模式可以用於構建強大的 Serverless 應用程序或將 Serverless 元素集成到現有架構中。


分享到:


相關文章: