花了1000G,終於弄清楚了Serverless (中):Serverless 架構的優缺點

Phodal發表於2019-03-01

Serverless 的優勢

在我使用 Serverless Framework 開發 AWS Serverless 應用的過程中,最方便的莫過於,第一次部署和第二次、第三次部署沒有什麼區別。只需要執行 serverless deploy,幾分鐘後,我們程式碼就執行線上上。如果是一個傳統的 AWS 應用,我需要 SSH 到我的伺服器上部署,這樣才能寫好我的自動部署指令碼。除此,我還需要擔憂這個過程中,有哪些使用者有使用。

除了,我覺得的部署方便,還有就是價格合理。我的 AWS EC2 例項上執行著我的部落格、以及其他的一些網路。然而,我那 PV 只有 500 左右的部落格,大部分時間都是在空轉。便覺得有些浪費,可是執行才收費的 Serverless 就不會有這樣的問題。可以讓我大膽地去使用這些服務。當然了,還有其它一些顯著的優勢。

降低啟動成本

當我們作為一家公司開發一個 Web 應用時,在開發的時候,我們需要版本管理伺服器、持續整合伺服器、測試伺服器、應用版本管理倉庫等作為基礎的服務。線上執行的時候,為了應對大量的請求,我們需要一個好的資料庫伺服器。當我們的應用面向了普通的使用者時,我們需要:

  • 郵件服務,用於傳送提醒、註冊等服務
  • 簡訊服務(依國家實名規定),用於註冊、登入等使用者授權操作

對於大公司而言,這些都是現成的基礎設施。可對於新創企業來說,這都是一些啟動成本。

減少運營成本

對於初創公司來說,他們沒有基礎設施,也沒有財力,也可能沒有能力去建設基礎設施。採用雲服務往往是最好的選擇,可以節省大量的資金。他們可以將注意力放在:創造對使用者有價值的產品上。如果一家創業公司採用雲服務,而不是自己搭建伺服器。那麼,他就會擁有更多的時間開發業務功能,而不是關注在這些。只需要為執行時的軟體付錢。

而採用函式計算的 Serverless 與雲伺服器最大的不同之處在於:雲伺服器需要一直執行,而函式計算是按需計算。按需計算就意味著,在請求到來的時候,才執行函式。沒有請求的時候,是不算錢的。

專案初期,其使用者數往往是緩慢增長的,而我們在選擇伺服器的時候,往往會依可能出現的使用者來估算。在這個時候,往往會浪費一些不必要的成本。不過,就算使用者突然間爆發,Serverless 應用也可以輕鬆處理。只需要修改一下資料庫配置,再重新部署一份。

降低開發成本

一個成功的 Serverless 服務供應商,應該能提供一系列的配套服務。這意味著,你只需要在配置檔案上寫下,這個資料庫的表名,那麼我們的資料就會儲存到對應的資料庫裡。甚至於,**如果一個當服務提供者提供一系列的函式計算模板,那麼我們只需要寫好我們的配置即可。這一系列的東西都可以自動、高效的完成。

在這種情況下,使用某一個雲服務,就會呼叫某一個系統自帶的 API 一樣簡單

當然,將應用設計成無狀態應用,對於早期的系統,可能是一種挑戰。除此,諸如 AWS 這樣龐大的系統,對於新手程式設計師來說,也不能容易消化掉的一個系統。

實現快速上線

對於一個 Web 專案來說,啟動一個專案需要一系列的 hello, world。當我們在本地搭建環境的時候,是一個 hello, world,當我們將程式部署到開發環境時,也是一個部署相關的 hello, world。雖然看上去有些不同,但是總的來說,都是 it works!。

Serverless 在部署上的優勢,使得你可以輕鬆地實現上線。

更快的部署流水線

實際上,Serverless 應用之所以在部署上有優勢,是因為其相當於內建自動化部署——我們在開發應用的時候,已經在不斷地增強部署功能。

在我們日常的開發中,為了實現自動化部署,我們需要先手動部署,以設計出一個相關無錯的部署配置,如 Docker 的 Dockerfile,又或者是 Ansible 的 playbook。除此,我們還需要設計好藍綠髮布等等的功能。

而在函式計算、Serverless 應用裡,這些都是由供應商提供的功能。每次我們寫完程式碼,只需要執行一下:sls deploy 就足夠了。在諸如 AWS Lambda 的函式計算裡,函式一般在上傳後幾秒鐘內,就能做好呼叫準備。

這就意味著,當我們和日常一樣,使用一個模板來開發我們的應用。我們就可以在 Clone 完程式碼後的幾分鐘內,完成第一次部署。

唯一的難點,可能是要選用什麼配置型別的服務,如選用哪個級別吞吐量的 DynamoDB、哪個記憶體大小的 Lambda 計算。

更快的開發速度

由於 Serverless 服務提供者,已經準備好了一系列的基礎服務。作為開發人員的我們,只需要關注於如何更好去實現業務,而非技術上的一些限制。

服務提供者已經向我們準備,並測試好了這一系列的服務。它們基本上是穩定、可靠的,不會遇上特別大的問題。事實上,當我們擁有足夠強大的程式碼,如使用測試來保證健壯性,那麼結合持續整合,我們就可以在 PUSH 程式碼的時候,直接部署到生產環境。當然,可能不需要這麼麻煩,我們只需要新增一個 predeploy 的 hook,在這個 hook 裡做一些自動測試的工作,就可以在本地直接釋出新的版本。

這個過程裡,我們並不需要考慮太多的釋出事宜。

系統安全性更高

依我維護我部落格的經驗來看,要保持伺服器一直執行不是一件容易的事。在不經意的時候,總會發現有 Cracker 在攻擊你網站。我們需要防範不同型別的攻擊,如在我的伺服器裡一直有黑客在嘗試密碼登入,可是我的部落格的伺服器是要金鑰才能登入的。在一次神奇的嘗試登入攻擊後,我的 SSH 守護程式崩潰了。這意味著,我只能從 EC2 後臺重啟伺服器。

有了 Serverless,我不再需要擔心有人嘗試登入系統,因為我都不知道怎麼登入伺服器。

我不再需要考慮系統底層安全問題,每次登入 AWS EC2,我總需要更新一遍軟體;每當我看到某個軟體有漏洞時,如之前的 OpenSSH,我就登入上去看一下版本,更新一下軟體。真 TM 費時又費力,還沒有一點好處。

唯一需要擔心的,可能是有人發起 DDOS 攻擊。而根據Could Zombie Toasters DDoS My Serverless Deployment?的計算,每百萬的請求,大概是 0.2 刀,每小時 360000000 個請求,也就 72 刀。

適應微服務架構

如我們所見在最近幾年裡看到的那樣,微服務並不沒有大量地替換掉單體應用——畢竟使用新的架構來替換舊的系統,在業務上的價值並不大。因此,對於很多企業來說,並沒有這樣的強烈需求及緊迫性。活著,才是一件更緊迫的事。

而 Serverless 天生就與微服務架構是相輔相成的。一個 Serverless 應用擁有自己的閘道器、資料庫、介面,你可還以使用自己喜歡的語言(受限於服務提供者)來開發服務。換句話來說,在這種情形下,一個 Serverless 可能是一個完美的微服務例項。

在可見的一二年裡,Serverless 將替換到某些系統中的一些元件、服務。

自動擴充套件能力

Serverless 的背後是 諸如 AWS Lambda 這樣的 FaaS(Function as a Services)。

對於傳統應用來說,要應對更多的請求的方式,就是部署更多的例項。然而,這個時候往往已經來不及了。而對於 FaaS 來說,我們並不需要這麼做,FaaS 會自動的擴充套件。它可以在需要時儘可能多地啟動例項副本,而不會發生冗長的部署和配置延遲。

這依賴於我們的服務是無狀態的,我們才能次無忌憚地不斷執行起新的例項。

Serverless 的問題

作為一個執行時,才啟動的應用來說,Serverless 也存在著一個個我們所需要的問題。

不適合長時間執行應用

Serverless 在請求到來時才執行。這意味著,當應用不執行的時候就會進入 “休眠狀態”,下次當請求來臨時,應用將會需要一個啟動時間,即冷啟動。這個時候,可以結合 CRON 的方式或者 CloudWatch 來定期喚醒應用。

如果你的應用需要一直長期不間斷的執行、處理大量的請求,那麼你可能就不適合採用 Serverless 架構。在這種情況下,採用 EC2 這樣的雲伺服器往往是一種更好的選擇。因為 EC2 從價格上來說,更加便宜。

引用 Lu Zou 在 《花了 1000G,我終於弄清楚了 Serverless 是什麼(上):什麼是 Serverless 架構?》上的評論:

EC2 相當於你買了一輛車,而 Lambda 相當於你租了你一輛車。

長期租車的成本肯定比買車貴,但是你就少掉了一部分的維護成本。因此,這個問題實際上是一個值得深入計算的問題。

完全依賴於第三方服務

是的,當你決定使用某個雲服務的時候,也就意味著你可能走了一條不歸路。在這種情況下,只能將不重要的 API 放在 Serverless 上。

當你已經有大量的基礎設施的時候,Serverless 對於你來說,並不是一個好東西。當我們採用 Serverless 架構的時候,我們就和特別的服務供應商繫結了。我們使用了 AWS 家的服務,那麼我們再將服務遷到 Google Cloud 上就沒有那麼容易了。

我們需要修改一下系列的底層程式碼,能採取的應對方案,便是建立隔離層。這意味著,在設計應用的時候,就需要:

  • 隔離 API 閘道器
  • 隔離資料庫層,考慮到市面上還沒有成熟的 ORM 工具,讓你即支援 Firebase,又支援 DynamoDB
  • 等等

這些也將帶給我們一些額外的成本,可能帶來的問題會比解決的問題多

冷啟動時間

如上所說,Serverless 應用存在一個冷啟動時間的問題。

據 New Relic 官方部落格《Understanding AWS Lambda Performance—How Much Do Cold Starts Really Matter?》稱,AWS Lambda 的冷啟動時間。

AWS 啟動時間
AWS 啟動時間

又或者是我之前統計的請求響應時間:

Serverless 請求時間
Serverless 請求時間

儘管這個冷啟動時間大部分情況下,可以在 50ms 以內。而這是對於 Node.js 應用來說,對於擁有虛擬機器的 Java 和 C# 可能就沒有那麼幸運了。

缺乏除錯和開發工具

當我使用 Serverless Framework 的時候,遇到了這樣的問題:缺乏除錯和開發工具。後來,我發現了 serverless-offline、dynamodb-local 等一系列外掛之後,問題有一些改善。

然而,對於日誌系統來說,這仍然是一個艱鉅的挑戰。

每次你除錯的時候,你需要一遍又一遍地上傳程式碼。而每次上傳的時候,你就好像是在部署伺服器。然後 Fuck 了,我並不能總是快速地定位出問題在哪。於是,我修改了一下程式碼,新增了一行 console.log,然後又一次地部署了下程式碼。問題解決了,挺好的,我刪了一下 console.log,然後又一次地部署了下程式碼。

後來,我學乖了,找了一個類似於 log4j 這樣的可以分級別紀錄日誌的 Node.js 庫 winston。它可以支援 error、warn、info、verbose、debug、silly 六個不同級別的日誌。

構建複雜

Serverless 很便宜,但是這並不意味著它很簡單。

早先,在知道 AWS Lambda 之後,我本來想進行一些嘗試。但是 CloudForamtion 讓我覺得太難了,它的配置是如此的複雜,並且難以閱讀及編寫(JSON 格式)。

考慮到 CloudForamtion 的複雜度,我是在接觸了 Serverless Framework 之後,才重新燃起了一些信心。

Serverless Framework 的配置更加簡單,採用的是 YAML 格式。在部署的時候,Serverless Framework 會根據我們的配置生成 CloudForamtion 配置。

在那篇《Kinesis Firehose 持久化資料到 S3》想著的資料統計文章裡,我們介紹了 Serverless 框架的配置。與一般的 Lambda 配置來說,這裡的配置就稍微複雜一些。然而,這也並非是一個真正用於生產的配置。我的意思是,真實的應用場景遠遠比這複雜。

語言版本落後

在 Node.js 6 出來的時候,AWS Lambda 只支援 Node.js 4.3.2;在 Node.js 9.0 出來的時候,AWS Lambda 支援到 6.10.3。

如下是 AWS Lambda 支援以下執行時版本:

  • Node.js – v4.3.2 和 6.10.3
  • Java - Java 8
  • Python – Python 3.6 和 2.7
  • .NET 核心 – .NET 核心 1.0.1 (C#)

對於 Java 和 Python 來說,他們的版本上可能基本都是夠用的,我不知道 C# 怎麼樣。但是 Node.js 的版本顯然是有點老舊的,但是都 Node.js 9.2.0 了。不過,話說來說,這可能與版本帝 Chrome 帶來的前端版本潮有一點關係。

節選自《Serverless 架構應用開發指南

相關文章