來源:架構師社區
無伺服器計算(Severless computing,簡稱 Serverless)現在是軟體架構圈中的熱門話題,國外三大雲計算供應商(Amazon、Google 和 Microsoft)都在大力投入這個領域,湧現了不計其數的相關書籍、開源框架、商業產品、技術大會。到底什麼是 Serverless?它有什麼長處/短處?我希望通過本文對這些問題提供一些啟發。
一些示例
介面驅動的應用(UI-driven applications)
我們來設想一個傳統的三層 C/S 架構,例如一個常見的電子商務應用(比如在線寵物商店),假設它服務端用 Java,客戶端用 HTML/JavaScript:
在這個架構下客戶端通常沒什麼功能,系統中的大部分邏輯——身份驗證、頁面導航、搜索、交易——都在服務端實現。
把它改造成 Serverless 架構的話會是這樣:
這是張大幅簡化的架構圖,但還是有相當多變化之處:
消息驅動的應用(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)調用。
狀態
當牽涉到本地(機器或者運行實例)狀態時 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 網關
我們前面還碰到過一個 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 還沒有這麼成熟的平台。
對比 NoOps
Serverless 並非「零運維」——儘管它可能是「無系統管理員」,也要看你在這個 Serverless 的道路走多深。
「運維」的意義遠不止系統管理,它還包括並不限於監控、部署、安全、網絡、支持、生產環境調試以及系統伸縮。這些事務同樣存在於 Serverless 應用中,你仍舊需要相應的方法處理它們。某些情況下 Serverless 的運維會更難一些,畢竟它還是個嶄新的技術。
系統管理的工作仍然要做,你只是把它外包給了 Serverless 環境。這既不能說壞也不能說好——我們外包了大量的內容,是好是壞要看具體情況。不論怎樣,某些時候這層抽象也會發生問題,就會需要一個來自某個地方的人類系統管理員來支持你的工作了。
對比存儲過程即服務
還有一種說法把 Serverless FaaS 看做「存儲過程即服務(Stored Procedures as a Service)」,我想原因是很多 FaaS 函數示範都用資料庫訪問作為例子。如果這就是它的主要用途,我想這個名字也不壞,但終究這只是 FaaS 的一種用例而已,這樣去考慮 FaaS 局限了它的能力。
我好奇 Serverless 會不會最終變成類似存儲過程那樣的東西,開始是個好主意,然後迅速演變成大規模技術債務。— Camille Fournier
但我們仍然值得考慮 FaaS 是否會導致跟存儲過程類似的問題,包括 Camille 提到的技術債。有很多存儲過程給我們的教訓可以放在 FaaS 場景下重新審視,存儲過程的問題在於:
儘管不是所有存儲過程的實現都有這些問題,但它們都是常會碰到的。我們看看是否適用於 FaaS:
第一條就目前看來顯然不是 FaaS 的煩惱,直接排除。
第二條,因為 FaaS 函數都是純粹的代碼,所以應該和其他任何代碼一樣容易測試。整合測試是另一個問題,我們稍後展開細說。
第三條,既然 FaaS 函數都是純粹的代碼,版本控制自然不成問題;最近大家開始關心的應用打包,相關工具鏈也在日趨成熟,比如 Amazon 的 Serverless Application Model(SAM)和前面提到的其他 Serverless 框架都提供了類似的功能。2018 年初 Amazon 還開放了 Serverless Application Repository(SAR)服務,方便組織分發應用程式和組件,也是基於 AWS Serverless 服務構建的。
需要的Java架構師方面的資料可以關注之後私信哈,回復「資料」領取免費架構視頻資料,記得要點贊轉發噢!!!