歡迎光臨
每天分享高質量文章

引入Serverless/FaaS時機到了?國外Hootsuite的Serverless架構實踐

導讀:業界有不少 FaaS/Serverless 方面討論,不少的架構師對引入類似的架構仍然存在一些顧慮,今天文章介紹一篇國外 Hootsuite 是用 Serverless 的案例,供考慮引入 FaaS 的同行參考。

Harry Huang,目前是 Hootsuite 的一名全棧工程師。Hootsuite 是一家創立於 2008 年來自加拿大的著名社交媒體管理工具。

背景

隨著業界公司都將架構演進到面向服務的架構 (Service oriented Architecture),越來越多的服務會轉移到“雲”中。

資料庫、檔案儲存、各種伺服器都正在慢慢地轉移到雲端,他們在虛擬容器中執行,而不是像以前一樣跑在專用的主機上。

最近流行起來的 FaaS(Function as a Service)可以使開發人員將“應用的業務邏輯”上傳到雲端,不用考慮伺服器或其他外部依賴,實質上是被抽象成了函式(Function)。

儘管如此,開發人員依然需要處理和“雲”密切相關的環節,比如上傳、部署、版本控制等等,這些複雜性與 FaaS 其他一些侷限性共同構成了 Serverless 架構。

動機

Serverless 框架允許我們將開發過程中和“雲”相關的部分抽象出來,開發人員可以直接編寫應用程式實際的業務邏輯程式碼。除此之外,Serverless 架構還具備其他優點,比如更低成本和易擴充套件。

既然這樣,我們會思考是否可以完全使用 Serverless 架構替代現有的架構樣式呢?下麵我們就著手構建一個功能齊全的,基於雲的,符合 Serverless 架構的應用。

我們構建了什麼?

我們建立了一個服務於 Hootsuite 內部工程師的小系統,工程師們可以列出自己的技能和興趣,可以建立、搜尋內部專案,也可以根據技能和興趣加入專案。

整個系統的後端完全基於 AWS Lambda,它是 Amazon 的事件驅動 FaaS 平臺,服務以 Lambda 函式的形式提供。

設計階段,我們需要函式能夠完成:

  • 將使用者和專案資訊儲存在資料庫中

  • 檢索資料庫中的使用者和專案資訊

  • 修改使用者和專案資訊

  • 搜尋使用者和專案

  • 傳送郵件/通知給使用者

  • 根據投票數和時間排列專案

另外,函式還要能夠整合其他服務。

整個專案中我們使用了以下 AWS 的服務[1]:

  • Lambda – 函式計算平臺

  • IAM&Cognito – 許可權和認證

  • DynamoDB – 資料儲存

  • S3 – 檔案儲存

  • SES – 郵件服務

  • Cloudwatch – 定時任務

  • Cloudfront – CDN,用來託管單頁應用程式(SPA)

  • API 閘道器 – 作為 Lambda 的 HTTP endpoint

以及一些第三方服務:

  • Algolia – 搜尋服務[2]

  • S3_website – 開源專案,用於在S3上部署靜態網站[3]

對於單頁應用的前端:

  • React – 響應式 UI

  • React-Bootstrap – 整合 React 的 Bootstrap 模版

同時,我們在專案中使用 Serverless Framework[4] 來測試和部署我們的基礎設施。這樣我們就不用操心 AWS 相關的配置或任何 DevOps 相關的事情,我們能夠專註於編寫應用的邏輯程式碼,照著里程碑快速推進。

約束

在正式開始之前,我們最好明確和統一一下認知。 Lambda,意如其名,就是匿名函式。因此,我們的後端實現基本上就限制於單一獨立的函式呼叫,我們可用的其他資源就是雲上的儲存和服務。這種 Serverless 架構樣式下我們就會面對一些約束:

無狀態性


Lambda 函式本身是事件驅動的,所以自然是無狀態的。來自客戶端的每個事件就是一個函式的單個呼叫,所以通常將狀態儲存於記憶體(如Redis)。在我們的例子中,我們使用DynamoDB 進行儲存和檢索。因此,我們的流程必須設計成單一的,獨立的,無狀態的函式組成。

長耗時的任務


目前,Lambda 函式有5分鐘的執行時長限制,顯然傳統的架構中是沒有這樣限制的。這使得需要長耗時的任務,比如處理資料流面臨挑戰性。如果有任務需要耗時5分鐘以上,那麼任務必須被拆分,同時還需要追蹤資料塊和狀態。對於定時任務或計劃任務,可以藉助 Cloudwatch 來設定時間間隔。

冷啟動


當 Lambda 函式無呼叫時,雲端通常會 Spin down 該函式。當再有呼叫時,函式的執行時容器會先將函式 Spin up。這意味著設定執行環境所產生的任何開銷,比如 JVM 層面的初始化等,都會增加函式執行的額外延遲。Neil Powers 和 Paul Cowles 之前給出了一個函式啟動時間的分析報告[5]。

對於後臺任務或者守護任務這倒沒關係。但是,對於我們正在構建的應用,冷啟動造成的延遲將會直接影響使用者的前端體驗。比如 Java 實現的函式,冷啟動時可以透過類似“ping 請求”,來盡可能降低延遲。對於我們的應用,最終選擇 Node.js 作為函式載體,因為它的冷啟動延遲最小[6]。

依賴

Lambda 的優點和缺點基本都源於 AWS Lambda 執行模型的工作原理。

  1. 首次呼叫函式時,AWS Lambda 將啟動一個執行容器並根據配置執行函式。

  2. 對於後續的呼叫,AWS Lambda 會嘗試重用該容器來執行函式。

  3. 如果流量較大請求較多時,AWS Lambda 將直接啟動更多的容器來提高吞吐,但每個新的執行容器都會產生冷啟動開銷。

由此可見,AWS Lambda 會自動進行水平擴充套件。但由於每個函式都有自己獨立的執行容器,所以每個容器都有建立開銷。這也意味著簡單得將一個 Lambda 函式拆分成幾個小的 Lambda 函式會進一步增加開銷。

由於執行容器是按需建立的,因此AWS Lambda 不能保證這些函式將在同一個記憶體空間甚至同一臺機器上執行。這與傳統架構模型不同,Lambda 函式不是“本地(locality)”的,在雲上需要來回傳遞狀態。

如果若干函式必須鏈式執行,那應該完全在雲端執行此操作,而不是在客戶端(比如 user facing 的功能)。這裡可以藉助 Amazon SNS 進行訊息傳遞,也可以使用 AWS Step Functions[7] 來執行函式工作流。

認證

這部分與 Serverless 架構關係不大,主要展示我們的應用如何透過 BaaS(Backend as a Service)來實現認證。所有認證邏輯都由 BaaS 提供。

我們應用使用者將和幾個 AWS 服務進行互動,我們需要一種方式來管理身份驗證以及不同 AWS 服務許可權和 API 訪問許可權的控制。藉助 Amazon IAM 和 Cognito,我們可以在控制檯內配置和管理許可權。

  1. 透過 IAM 策略,可以指定允許或不允許的操作,比如上傳到 S3

  2. 策略可以系結到角色

  3. 將角色新增到 Cognito Identities 中,就建立一類使用者

這樣使用者透過驗證身份,獲得使用者所屬角色,繼而獲得各種許可權。我們能夠處理,維護使用者目錄,我們也可以透過令牌進行身份驗證,同時所有內容都儲存在雲中,工作流程如下所示。

  1. 客戶端將身份驗證資訊傳送給 IdP(Identity Provider)

  2. 我們的 IdP(Cognito 使用者池)向客戶端和 Amazon Federated Identities 傳送確認令牌

  3. 客戶端將令牌傳送給 Federated Identities 並驗證令牌

  4. Federated Identities 從 IAM 查詢角色並傳回臨時訪問憑證

  5. 使用者就可以使用憑證訪問我們應用的 API 和服務了

完整的 Serverless 架構

客戶端透過 Amazon API Gateway 來呼叫我們的 Lambda 函式。 Lambda 函式再呼叫其他服務的 API 並傳回相應的結果。這是一個典型的 Lambda 函式工作流:

還有其他幾種呼叫 Lambda 函式的方式。 S3,DynamoDB,SES 甚至 Amazon 的 Alexa 都可以觸發 Lambda 函式。例如,我們使用 Cloudwatch 設定計劃事件來觸發 ranking 函式。

另一個常用的是 Amazon Cognito 的預註冊觸發器(pre-signup trigger)。這樣在註冊或登入工作流程的每個步驟都可以觸發事件並呼叫函式,我們就可以設計靈活的流程來定製身份驗證。

搜尋

Serverless 架構很棒的一個特點就是很易於和其他服務整合。 基於資料庫提供快速,複雜搜尋的能力通常需要類似 Elasticsearch 這樣的系統。這與我們的 Serverless 架構相違背,因此我們將搜尋的能力委託給 SaaS(Software as a Service)服務商 Algolia。這樣我們就能夠使用它的 API 來索引我們的資料,並透過 Lambda 函式執行查詢。

如下圖:

我們的 Lambda 函式基本上取代了傳統架構中的“服務”層。

前端

對於單頁的 React 應用,透過 API 閘道器與背後的各個函式通行。所有靜態資源託管在 S3 上,並透過 Cloudfront 提供服務。透過Serverless 架構,我們希望以完全獨立的方式來構建應用中的元件,就像前面羅列的做法。

開發 Lambda 函式

設定好 AWS Lambda 之後的實際開發過程簡單且高效。將你的函式新增到 Serverless Framework 的配置檔案後,唯一需要去做的就是編寫實際的業務邏輯函式。

Serverless Framework 可以模擬請求來測試本地的 Lambda 函式。任何輸出和異常都呈現在終端裡,就像透過 IDE 執行和除錯其他程式一樣方便。

在雲端,任何異常、日誌或呼叫都會被自動記錄下來。在 Cloudwatch 上可以檢視部署的每個函式的每個版本產生的日誌和統計資訊。因此如果需要追蹤生產環境中出現錯誤的請求,就可以透過 Cloudwatch 輕鬆完成。

至於上傳和部署,就像在終端中執行單個命令一樣簡單。以前,每次要上傳函式時都需要進行一些 Lambda 上的配置和操作。這要求開發人員自己編寫除錯一個指令碼來自動執行這個過程。但使用 Serverless Framework,所有這些過程都是內建的和自動化的。與伺服器有關的任何事情都被抽象出來了,真的感覺開發過程是“無伺服器”(server-less)的。

優點

低成本

AWS 的許多服務都有免費套餐,可以滿足開發階段的使用。即便是投入生產環境,Lambda 的定價是基於使用量的,所以如果一個函式沒有被使用,那就不會產生任何費用。Serverless 架構/FaaS 是開發產品原型和輕度使用量應用的更便宜選擇。

降低 Devops 的負擔

隨著 FaaS 的推出,DevOps 大部分負擔已經從“維護主機以及搭建基礎設施”轉移到“維護程式碼和雲服務商”。

隨著 Serverless Framework 的誕生,開發人員的程式碼越來越接近生產環境,減少了大量 DevOps 工作。正如我們這個專案所體現的,設計架構和搭建伺服器的時間較少,而大部分精力被用來開發實際應用。

確保微服務化

FaaS 樣式的後端會客觀上確保微服務化。比如身份驗證和搜尋服務,需要一個連續執行的服務,並不適合直接構建在 AWS Lambda 上,我們必須將它們作為單獨的微粒度的服務來構建,或者委派給其他已經存在的服務(就像前面說的 BaaS 服務)。

然後我們的應用可以透過一個函式和它們的 API 整合,它們服務的治理是獨立於我們的應用,但整合用的函式就可作為一個微服務來管理。

微服務架構的優點不必多言,建立一個 Serverless 架構的應用會客觀上確保你構建真正的微服務,並從中受益。

下一步計劃?

Serverless/FaaS 技術在過去一年中獲得了顯著的增長和發展[8]。

我們的專案以及這篇文章都已經證明,Serverless 是開發和部署微服務應用或是 Web 應用的廉價,快速的最佳方法。隨著相關技術的不斷發展,未來容器技術和 Serverless 趨勢很可能融合。即使沒有,擁抱 Serverless 都是值得的。


參考資訊

[1] https://aws.amazon.com/

[2] https://www.algolia.com/

[3] https://github.com/laurilehmijoki/s3_website

[4] https://serverless.com/

[5] http://code.hootsuite.com/accelerating-cross-platform-development-with-serverless-microservices/#more-4730

[6] https://www.bouvet.no/bouvet-deler/comparing-java-and-node.js-on-aws-lambda

[7] https://aws.amazon.com/step-functions/

[8] https://serverless.com/blog/ultimate-list-serverless-announcements-reinvent/?rd=true/

文作者 Harry Huang,由魏佳翻譯。基於移動閱讀的考慮,排版相比原文有所調整。轉載本文請註明出處,技術原創及架構實踐文章,歡迎透過公眾號選單「聯絡我們」進行投稿。


推薦閱讀


高可用架構

改變網際網路的構建方式

長按二維碼 關註「高可用架構」公眾號

贊(0)

分享創造快樂