使用 Node.js + serverless framework + AWS Lambda 打造可擴展、更穩定而且更經濟的架構
Server 是伺服器,serverless 是什麼?
serverless 是讓開發者可以完全不必管理伺服器,自動化部署函式的架構。
傳統的網路服務部署,都仰賴開發者在伺服器上設置並管理程式碼的運作,後來出現了容器化(dockerize)的技術,讓開發者可以把應用程式打包成容器,在不同的環境下也得以自動化部署,大大減輕了部署的工作量與不確定性。
同時市面上也有許多雲端主機商(例如 Heroku),協助開發者自動化部屬應用程式,不必管理伺服器。serverless 是更進一步的的解決方案,透過 serverless,開發者不只不用管理伺服器,還可以自動化部署函式。
透過將巨量機器的運算資源抽象化,得以達成將很多機器的運算資源分配給很多函式運作的目標,因此這樣的服務通常由擁有大量機器的雲端服務商所提供,例如 Google 的 GCP,Amazon 的 AWS。
使用 AWS Lambda 執行程式碼,不必佈建或管理伺服器。您只需為使用的運算時間支付費用。 — https://aws.amazon.com/tw/lambda/
為什麼要使用 serverless 架構?
不必管理 server 的好處顯而易見,由雲端服務商統一管理主機能夠夠更穩定的提供服務,同時也免除了環境設置,管理、升級、備份主機的種種需求。在 serverless 的架構下,開發者能夠不必擔心關於部署的細節,真正專注在開發應用程式的基礎單位,函式。
這麼好的架構,一定很貴吧?在大多數情況下,會比較便宜。
在 AWS 中雲端伺服器就算是閒置時仍然會收費,相反的,serverless 以函式為個別的執行時間以及記憶體計費,也就是用多少付多少。這在大多數的情況下都會比較便宜。
同時 AWS 也提供了優渥的免費額度:
AWS Lambda 免費用量方案包含每月 100 萬個免費請求以及每月 400,000 GB-秒的運算時間。 — https://aws.amazon.com/tw/lambda/pricing/
應用場景:我應該在什麼時候採用 serverless?
無狀態的函式最適合使用 serverless 架構。
當一個函式沒有使用外部的資源 (database 、其他 api) ,並且需要有穩定的效能、可用性時,serverless 架構可以發揮最大的優勢。
假如產品中有個關鍵功能必須要生成特定檔案,這個功能有可能佔用較多的記憶體與運算資源,需求上必須保證這個功能穩定且順暢的運作,該怎麼做?你可以升級伺服器的規格(升級到可以處理「你能預估的最多使用者同時使用的情形」),或者,把這個功能獨立在 serverless 的架構中,與原本的伺服器以 web api 整合。
如果這段函式是用以下的程式語言寫成,你甚至可以沿用幾乎所有程式碼,遷移到 AWS Lambda。
Lambda 原生支援 Java、Go、PowerShell、Node.js、C#、Python 和 Ruby 程式碼
為什麼要使用 Serverless framework ?
這篇文章目前為止提到的 serverless 指技術架構,此處所提的 serverless framework 指協助串接雲端主機商的產品。透過 Serverless framework,我們可以更快速、容易的設定 AWS Lambda 參數與開發函式。
Serverless framework 提供以下優點:
yaml configuration
可以透過一份 yaml 的設定檔統一管理整個 serverless 的服務設定,包括 memory size, timeout, resource 等等。藉由這樣一份設定檔,在每次部署 serverless 的時候可以更不容易出錯,因為你可以透過 git 看出哪些地方有修改,藉此達到更穩定的服務。
監控管理系統
serverless framework 提供了美觀的儀表版,並且會在使用率、錯誤率突然竄升的的時候提示警告,同時提供 webhook 可以整合 slack,當 serverless 出錯時,可以在 slack 取得資訊。
其中一個我覺得很實用的功能是,serverless framework 會根據過往的 function 執行狀況,建議你更適合的 memorySize、timeout,也就是,他會幫你省錢。
此外,透過使用 serverless framework 生態的 plugin,可以使用更強大的功能:
serverless-offline : 在本地端建立一個測試用的 endpoint
serverless-plugin-typescript : 支援 Typescript
接下來將會介紹如何使用 serverless framework 以及 Node.js 設置一個 serverless project。
如何設置一個 Node.js serverless project
首先,必須安裝 serverless
npm install -g serverless
安裝成功後,輸入指令初始化 project,此時 CLI 會詢問專案的名稱以及相關的設定
serverless
進入到剛剛創建的專案資料夾後,可以看到這些檔案。
<your project>
├── .gitignore
├── handler.js
└── serverless.yml
在 handler.js
可以看到有一個 function 輸出成 module hello
。
這個 hello
對應到 serverless.yml
中:
serverless.yml
把 function 以 module 輸出,然後在設定檔的 functions
中引入,就可以成功設置 function 了。
在本地環境 Debug
為了要在本地架設 serverless service endpoint,必須要安裝 plugin serverless-offline。
yarn add -D serverless-offline
// 或者
npm install serverless-offline --save-dev
然後編輯 serverless.yml
- 加入 plugins: serverless-offline
- 在 hello 這個 function 中給入 http 的設定
...
plugins:
- serverless-offline
functions:
hello:
handler: handler.hello
events:
- http:
path: /hello
method: get
...
設定完成後我們就可以啟動 serverless offline,輸入指令:
serverless offline
若設置成功,畫面應該會跑出這些資訊,在瀏覽器打開 http://localhost:3000/hello 就可以看到 serverless 回傳的值了!
這就是一個簡單的 serverless function。
如何使用 serverless function 取得參數和回傳資料
打開 serverless offline ,
然後用瀏覽器開啟: http://localhost:3000/hello?foo=bar
在預設的 handler hello
中以 input
回傳了 event 物件,因此可以直接在 queryStringParameters 中看到
{
“foo”: “bar”
}
這就是我們帶在 url 中的參數。如果 function 使用 HTTP POST,那麼 body 則會在 event.body。
透過觀察 handler.js 中的hello
也可以發現,回傳物件中的 body 就會是回傳物件。額外需要注意的是,如果你的 function 不是 async function,回傳值必須要使用 hander function 的第三個參數 callback
回傳物件以及錯誤。
部署 Serverless function
要部署 serverless 之前,必須先:
完成之後,輸入指令
serverless deploy
有可能 serverless 會告訴你少了什麼權限、設置或其他問題,會需要一一解決。常見的問題是 npm 套件的系統環境問題。
Build npm 套件的環境問題
由於 Lambda 的執行環境是在 Amazon 為 Lambda 客製化的 Linux 上,如果你使用的 npm 套件依賴於系統的函式,那麼在本地 build 的程式就會出錯,此時,你可以使用 docker 模擬 Lambda linux rebuild 。
docker run — rm -v $PWD:/var/task lambci/lambda:build-nodejs10.x npm install
如果需要更詳細的文件可以參考這裡:
如果成功的話,就會顯示出 Lambda 的 endpoint,部署就完成了!
延伸閱讀
AWS Lambda Node.js 文件:https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html
AWS Lambda 介紹:
Serverless framework 介紹: