本文由 Xavier Lefèvre 發表在 medium.com,經原作者授權由 InfoQ 中文站翻譯并分享。
Lambdas 如此吸引人有兩個原因:自動縮放功能(擴容、減容)以及按使用量計價的模型。為了利用這些能力 ,并從無服務器架構的優勢中獲得最大利益 ,我們需要其他基礎架構組件也具有同樣的靈活性。
在一個 Web 項目中,這樣的架構是怎么樣的呢?
在 Theodo,我們熱愛無服務器架構技術,并將這項技術應用到越來越多的項目中。 今天, 一些服務和模式開始被行業廣泛使用。所以,我們決定分享 Web 應用的基礎架構最佳實踐。如果你不了解無服務器架構,并且希望找到回答這些問題的高級指南,那么你就來對地方了!
先來看看這個簡單粗暴的全文“劇透”吧?。▌e擔心,我們將深入講解其中各個方面)
在上述圖表中, 方框代表的是存在于大多數無服務器架構中的典型并且明確界定的領域或技術功能。他們不一定代表微服務或 CloudFormation 術語中的堆棧(Stack)(我們在下文會提到) 。
我們的實踐
我們的目標是擁有一個穩健且完全托管的系統,并使開發者擁有舒適的開發體驗。為了實現這個目標,我們選擇了:
AWS
云技術的競爭很激烈:亞馬遜云服務(AWS)、谷歌云服務(GCP)、微軟云服務(Azure)、IBM 云服務、阿里云服務。他們都提供了一些令人驚艷的產品,并且以前所未有的速度在快速發展。 Ben Ellerby 在這篇文章中比較了前三名的云服務提供商,而我們更青睞于AWS 的解決方案。在無服務器架構方面,AWS 是最先進的。借助AWS 的解決方案,我們可以盡可能接近無服務器架構。為了說明這一點,我們將在下文中詳細介紹構成我們架構模塊的每個AWS 服務。
TypeScript 中的 Node
JAVAScript 是世界上最受歡迎的編程語言之一,因此它有一個龐大的社區(請參閱 GitHub 統計信息)!根據 Datadog 的調查,無服務器架構的世界中也是如此。盡管 Python 以 47%的占有率領先,但目前已部署的 Lambdas 中有 39% 是運行 JavaScript 的。 TypeScript 使該語言更進一步,增加了一層額外的保護。最后, 在絕大多數用例中, Lambdas 中的 JavaScript 都運行得很好。
Serverless Framework
無服務器架構框架完成了大部分基礎架構即代碼(Infrastructure as Code, IaC)的工作(基于 CloudFormation )。你定義一個對 HTTP 事件做出響應的 Lambda 函數,無服務器架構框架將自動部署相關的 API Gateway 資源、相應的路由以及新的 Lambda 函數。當我們達到框架的極限,并且需要更復雜的服務配置時,我們只需簡單地添加一些 CloudFormation 即可 。
細粒度的 Lambda 函數
Lambda 是一個函數,它有自己的工作任務,并且能做得很好。我們的前端需要獲得一個項目列表嗎?為這個功能新建一個 Lambda 函數吧。當用戶注冊后,我們需要發送確認電子郵件嗎? 為這個功能新建另一個 Lambda 函數吧。當然,某些特定的代碼(例如數據實體)可以分解成小的單元,并在專用的 utilities 文件夾中共享。但一定要非常小心這些代碼,因為任何更改都會影響所有相關的 Lambda 函數。而且因為每個 Lambda 是可以獨立測試和部署的,因此我們可能會遺漏一些內容(這時 TypeScript 就派上用場了)。
分解成微服務
為了不讓團隊互相影響,并且避免巨大的 package.json 和 serverless.yml (CloudFormation 的資源限制數量為 200)以及過長的 CloudFormation 部署時間,同時也為了方便我們在代碼庫中定位,并在所有 Lambdas 函數之間明確清晰的團隊職責:我們定義了微服務中劃分項目的邊界。Ben Ellerby 在這篇文章中寫了一個方法, EventBridge Storming ,來幫助定義這些界限。
在我們的單體代碼庫中:一個微服務 = 一個 CloudFormation 堆棧 = 一個 serverless.yml + package.json。此外,微服務會屬于自己的數據實體,這些數據實體不會與其他微服務共享。
我們早時推薦完全使用 JavaScript,但出于種種原因,你可能想要使用另一種語言,或者可能希望逐步遷移到 JavaScript 中的無服務器架構。在無服務器架構中,微服務的極端優勢是你可以在架構中輕松混合多種技術棧,同時也能夠保持微服務之間的抽象接口的簡單性和一致性。
以事件驅動的方式交流
這些微服務需要完全獨立,如果其中一個微服務出現事故,或者我們正在對另一個微服務進行重大改動,這對于系統其他部分的影響應該越小越好。為實現這個目標,Lambdas 函數僅通過 EventBridge 這個無服務架構的事件總線來和其他 Lambdas 交流。在這篇文章中, Ben Ellerby 詳細敘述了為什么EventBridge 用途這么大 。
詳解每個架構模塊
現在我們已經介紹了一些背景知識,接下來讓我們講解上面那副令人望而卻步的無服務器架構圖中的每一個架構模塊,并且詳細介紹在AWS 中最具有無服務器架構精神的服務。
前端開發
我們優秀的無服務器后端需要以某種方式為前端提供數據。為簡化與AWS 耦合的前端開發,我們利用了 Amplify 。Amplify 囊括了幾個不同的東西:一個命令行工具、一個基礎架構即代碼(IaC)工具、一個 SDK 和一套 UI 組件。我們利用前端的 JS 的 SDK 來加快與其他資源(比如用于認證的 Cognito)的集成,這些資源通常是通過其他 基礎架構即代碼工具(比如無服務架構框架)來部署的。
網站托管
如今,大多數網站是單頁應用(Single Page Application,SPA),它們是功能齊全的動態應用程序,被打包在一組靜態文件中。這些文件是在用戶的瀏覽器首次訪問 URL 時下載的。在 AWS 環境中,我們在 S3(一個文件存儲服務)中托管這些靜態文件,并通過 CloudFront (一個內容分發網絡,即 CDN)來公開。
話雖如此,現在的趨勢顯然在朝著諸如 Next.js 之類的 (無)服務端渲染(Server Side Rendering,即 SSR)發展。要在無服務器架構中運行一個 SSR 網站,我們可以利用 CloudFront 中的 Lambda @ Edge。這使我們能夠使用盡可能更接近用戶端的 Lambdas 函數來進行服務端渲染。請查看這篇文章以深入探討該主題。
域名與證書
在我們網站中,我們希望使用相比于原始自動生成的S3 URL 更好的URL,為了做到這一點,我們使用Certificate Manager 來生成證書,并將其綁定在CloudFront,并使用Route 53 來管理域名。
業務邏輯接口
現在,我們的網站需要連接后端,以獲得和推送數據。為此,我們使用 API Gateway 來處理 HTTP 連接和路由,并為每個路由同步觸發一個 Lambda 函數。我們的 Lambda 函數包含與 DynamoDB 通信的業務邏輯,以便存儲和使用數據。
如上文所示,我們是事件驅動的,這意味著我們會立即回復用戶請求,然后,繼續在后臺異步地處理請求。例如,DynamoDB 提供了流(Streams),它可以對任何數據改動作出反應,并且異步地觸發 Lambda 函數。大多數無服務器架構的服務都有類似的功能。
DynamoDB 本身是一個非常大的話題,在這篇文章中, Rob Cronin 解答并化解了 了一些關于“臭名昭著的”NoSQL 數據庫的一些經典問題和疑慮。
異步任務
我們的架構是事件驅動的,所以我們許多的 Lambda 函數都是異步的,通常是由 EventBridge 事件、S3 事件、DynamoDB 流等事件觸發。例如,我們可以有一個異步 Lambda 函數,負責在成功注冊后發送歡迎電子郵件。
在分布式異步系統中,故障處理是非常重要的。所以對于異步的 Lambda 函數,我們使用它們的死信隊列(Dead Letter Queue,DLQ),并且將最終的故障信息首先傳遞給 Simple Notification Service(SNS),然后再傳給 Simple Queue Service(SQS)。我們現在必須這樣做,因為 AWS 暫時還不支持將 SQS 直接連接到 Lambda DLQ 上。
后端向前端的推送
有了異步的操作,前端不能在等待一個 XHR 響應時僅僅顯示一個加載頁面。我們需要后端的預備狀態和數據推送。為此,我們利用了 API Gateway 的 WebSocket,這個 API 可以使 WebSocket 保持連接狀態,并且僅在在收到消息時觸發 Lambdas 函數。我寫了 一篇文章深入討論了相比較于其他解決方案,為什么我們選擇了 WebSocket,以及如何實現它。
文件上傳
處理Lambda 的文件上傳流(Stream)可能會造成較大的開銷。相較于這個方案,S3 還提供了一個功能,使得前端能使用由Lambda 生成的、簽名(安全)的上傳URL 來直接上傳文件到S3。
用戶與認證
Cogito 有我們所需要的所有東西:認證、用戶管理、訪問控制以及外部身份提供商集成。盡管大家知道它使用起來有些復雜,但它確實可以為我們做不少事情。和其他服務一樣,它由專用的 SDK 來與 Lambda 交互,并且可以分發事件以觸發 Lambda。在我們的例子中,我們說明了將 原生Cogito 授權者綁定在我們的API Gateway 路由上的可能性。我們也暴露了一個用于刷新身份驗證令牌的Lambda 函數和一個用于獲取用戶列表的Lambda 函數。
然而,還有一個忠告:Cogito 現在還不是用于管理你整個用戶數據的數據庫不二之選。它有一些不足,例如,你可以擁有的屬性數量是存在限制 的 。如果你需要一些靈活性,你最好將自定義的屬性存在DynamoDB 中。
狀態機
在某些情形下,我們的邏輯和數據流可能會非常復雜。如果直接在Lambda 函數內部手動維護和操作這些數據流,你可能會難以跟蹤和理解正在發生的事情。因此,AWS 為我們提供了專門提供了一個服務:可視化工作流服務 ( Step Functions )。
我們通過 CloudFormation 來聲明狀態機:包括每個子步驟和狀態、每個希望得到的結果和不希望得到的結果,并且將一些原生操作(例如等待、選擇)或者一個 Lambda 掛載在這些步驟上。然后,我們可以通過 AWS 界面實時看到我們的服務可視化地運行(并且還能查看日志)。在其中的每個步驟中,我們可以定義重試和失敗處理邏輯。Ben Ellerby 在 這篇文章中進一步詳細介紹了該服務。
舉一個更加具體的例子,假設我們希望通過 SaaS 發送一個電子郵件廣告,并且能夠確保該廣告已經發送完畢:
- 步驟 1,Lambda:要求 SaaS 發送電子郵件廣告系列并獲取廣告的 ID。
- 步驟 2,任務令牌 Lambda:從 Step Function 中獲得回調令牌,將其鏈接到廣告 ID,然后等待來自 SaaS 的回調。
- 步驟 3,(在任務流之外的)Lambda:在廣告的狀態發生改變時(待定、存檔、失敗、成功),從 SaaS 通過一個鉤子函數調用,然后通過對應的回調令牌根據新的廣告狀態來繼續任務流。
- 步驟 4,選擇(Choice):基于狀態選擇,如果這個廣告還沒有成功,回到第二步。
- 步驟 5,(結束)Lambda:在廣告發送后,更新用戶。
這篇文章深入講述了任務令牌(Task Tokens )是如何工作的。
安全
Identity and Access Management (IAM) 幫助我們非常細粒度地管理任何 AWS 訪問,不 管是開發人員的訪問、持續集成與持續交付流程 , 還是 AWS 的服務調用另一個服務。它乍看之下可能令人望而卻步,但它的優點是十分先進和精細,要求我們認真思考某個特定的“消費者”被允許操作的每個微小行為。這意味著我們基礎架構中的每一層都是受到保護的。 Ben Ellerby 在 ServerlessDays 在 Nashville 的峰會中提到了這個話題。
對于非常敏感的數據,比如 SaaS 的 API 密鑰,我們將其安全地存儲在 System Manager 中的 Parameter Store 中。無論是來自我們的無服務器架構框架還是 CloudFormation 文件,甚至是來自我們的代碼的訪問,都必須通過對應的 SDK 來請求它們。值得一提的是, AWS Secrets Manager 也可以完成類似的工作。并且 Key Management System 也可以幫助我們管理加密密鑰。
如果對該話題感興趣,我推薦來自 Sat G 的 這篇文章,關于無服務器架構中的安全問題在此文章中有更詳細的概述。
監控
CloudWatch 是監控服務的業界標準。所有 AWS 服務都有基本的自動指標和日志發送到發送到 CloudWatch,以向我們提供一些基本信息。我們可以做更多的事情:將自定義的指標和日志發送到 CloudWatch,創建指標儀表板,在超過閾值后觸發警報,進行復雜查詢來挖掘數據并且把它們顯示到自定義的圖表中。
我們仍然在尋找其他選擇,比如 X-Ray ,它的目標是在我們整個分布式系統中端到端地追蹤請求,然后以非常直觀和動態的方式表示它。只不過現在這個追蹤服務時不時會失敗,因為它還不支持某些 AWS 服務,比如 EventBridge(而這在我們的架構中是核心)。
另一個服務,基于 X-Ray 和 CloudWatch 構建的 ServiceLens ,看起來棒極了 。此外,還有一些有前景的外部解決方案,比如 Thundra, Epsagon 或 Lumigo,但我們現在還沒有機會完全嘗試它們。
Theodo 自豪地將其工具添加到了生態系統中:如果你想改善你的本地開發和可觀察性,那么你應該嘗試 Serverless-Dev-Tools。
總結
無服務器世界正在飛速發展。一旦開始了解它,感覺就像是發現一個全新的宇宙,充滿了萬物俱興的一切可能性,這太令人興奮了!
在 Theodo,我們每周都會發現新的服務、工具和模式。這就是為什么我希望本文盡可能是最新的,以跟上步伐并分享我們當前的最佳做法。因此,別忘記在 Twitter 上關注我,那里還會有更多更新。
現在你已經了解了無服務器架構的基礎知識,我們打算證明它與經典的服務器架構相比便宜得多!因此,我們為此構建了成本計算器。只需要少量“簡單的”輸入,你將看到它可能要花多少錢。如果有興趣,請通過 Twitter 與我聯系。當然,我會在未來幾周內(譯者:在本文翻譯完畢時,該推文已經發送)發布有關此消息的推文。
作者介紹:
Xavier Lefèvre 現任 Theodo 技術副總裁(VP Engineering)。Theodo 是一家軟件咨詢和開發機構,在巴黎(作者居住地)、倫敦和紐約設有辦公地點。 他從小就熱愛高科技,如今他有機會從事自己所熱愛的技術行業。 他最近專注于無服務器架構,堅信這項技術將在行業中取得重大飛躍,并將他的關注和精力放在于客戶更相關的話題上。 如果您想就此話題進行交流,請隨時在 Twitter 上關注 / 聯系他。
英文原文:
https://medium.com/serverless-transformation/what-a-typical-100-serverless-architecture-looks-like-in-aws-40f252cd0ecb