Serverless 多函式開發示例

01。 什麼是 Serverless?

Serverless 的定義和理解在不同的角度和場景會有不同的解讀,AWS 將 Serverless(在 AWS 雲上) 定義為 “是一種用於描述服務、實踐和策略的方式,使您能夠構建更敏捷的應用程式,從而能夠更快地創新和響應變化”的一種服務。 而紅帽認為 Serverless 是 “可使開發人員專注構建和執行應用,而無需管理伺服器” 的一種開發模型,並進一步將 Serverless 的產品分為兩類:BaaS(後端即服務,讓開發人員訪問各種各樣的第三方服務和應用) 與 FaaS(功能即服務,開發人員編寫邏輯,部署到完全由平臺管理的容器中,然後按需執行) 兩種形態。 而 Serverless Framework 則認為 Serverless 是“一場由開發人員和企業推動,讓單個開發人員可以完成高流量的應用開發,同時只將精力集中在產生價值的方面”的運動,

不管哪個方面,哪種角度,Serverless 都具有以下共同特點:

快速開發,快速部署

按量付費,降低成本

自動擴容,無需維護

而目前都是基於各個雲廠商的 FaaS 服務來實現,如: 騰訊雲的 SCF, AWS 的 Lambda, Azure 雲的 Azure Funcitons 等。

Serverless 解決什麼問題?

隨著計算能力的加強,系統複雜度的增加,使用者規模的增長,軟體問題(如下, 也稱為軟體危機)也會發生指數型的增長。

軟體開發進度難以預測

軟體開發成本難以控制

軟體產品質量無法保證

軟體產品難以維護

而 Serverless 則可以透過以下方式提出了對於軟體危機問題的解決方案:

透過函式方式將系統功能拆分為更小的顆粒度,更便於設計,開發,測試和維護。

透過按量計費大幅度減少資源閒置時的開銷費用,降低伺服器成本。

透過自動擴容以及雲平臺的支援,大幅減少運維工作量以及軟體維護成本。

同時在現在普遍倡導敏捷工作方式的現代工作環境中,Serverless 也為快速驗證想法、迭代功能提供了開發方式的最佳實踐,同時而不需要擔心程式碼改動會影響系統的其他功能,也無需考慮部署前的伺服器配置以及部署後的維護工作。

02。 Serverless Framework

Serverless Framework 是業界非常受歡迎的無伺服器應用框架,透過與眾多一流雲供應商如騰訊雲,AWS 等的緊密合作,為廣大開發者提供無需關心底層基礎設施,即可編寫和部署程式碼的無服務開發體驗。

Serverless Framework 同時提供資源管理、自動伸縮、統計分析等能力,讓廣大開發者可以節省運維成本,真正做到“按量付費”的同時,也無需花費精力處理日誌收集、異常統計等任務。

Serverless Framework 透過 CLI 工具與騰訊雲緊密合作,為中國使用者提供了基於元件(Serverless Components)的完整解決方案。覆蓋了無服務應用編碼、測試、部署等全生命週期,同時切合中國使用者的使用場景和習慣。

為什麼選用 Serverless Framework?

透過 Serverless Framework 的短短几行配置檔案和 CLI 工具,開發者就可以額外獲得:

在本地進行函式開發,並一鍵部署到雲端,無需額外適配雲函式,也無需登入控制檯。

支援將傳統開發框架的應用 (如:Express, Next。js, Flask, Laravel 等)部署為 Serverless 應用。

在本地對函式程式碼進行除錯,或使用遠端開發模式在本地實時檢視部署服務的日誌輸出,並進行除錯。

透過簡單配置即可完成所有基礎設施配置(如:API 閘道器、COS 儲存、DB 連結等)

快速切換應用的部署環境(開發,演示,生產),地區。

更詳細輕鬆的瞭解應用狀態,檢視日誌、報錯統計等資訊。

03。 多函式開發示例

本示例使用 Serverless Framework 的多函式元件(multi-scf)和 PostgreSQL 元件(postgresql)實現,實現以下 3 個 API 介面。

GET /todos/ 獲取所有的 todo 事項

POST /todos/ 建立新的 todo 事項

POST /todos/{id}/actions/complete 完成 todo 事項

並使用 Serverless Framework 提供的 invoke 和 logs 功能進行除錯以及檢視生產環境實時日誌。

本示例相關程式碼可以在 Git 倉庫 中獲取。

步驟 1: 安裝 Serverless Framework

執行以下命令安裝 Serverless Framework

$ npm install serverless -g

如果之前您已經安裝過 Serverless Framework,可以透過下列命令升級到最新版:

$ npm update serverless -g

此命令會安裝最新的 Serverless Framework 到你的計算機,安裝成功後可以透過 serverless 或者 sls 開始使用 Serverless Framework

步驟 2: 初始化多函式專案

$ sls init multi-scf-nodejs ——name sls-demo-msn-todo

此命令會使用應用模板 multi-scf-nodejs 初始化名為 my-multi-scf-demo 的應用目錄。初始化成功後該目錄結構為

。├── README。md├── index。js└── serverless。yml

這裡的檔案用途如下:

index。js:函式檔案。

serverless。yml:Serverless Framework 配置檔案。

app:應用名稱,會作為應用識別的唯一標識。

stage:應用環境,透過不同環境,部署不同的應用例項。

component:元件名稱

name:元件例項名稱

inputs:元件部署的輸入引數

步驟 3: 連結資料庫

因為 Serverless 是無狀態的(執行後就會銷燬), 所以這裡需要連結資料庫用來持久化 todo 資訊。新增資料庫需要先借助 VPC 網路連線。

1. 新增 VPC

建立子目錄 vpc 並在子目錄中新增新的 serverless。yml 檔案如下:

component: vpc # [必選]要使用元件,更多元件請檢視 https://github。com/serverless-componentsname: sls-demo-msn-vpc # [必選]元件例項名稱inputs: region: ap-guangzhou # 例項所屬地區 zone: ap-guangzhou-2 # 例項所屬地區區域 vpcName: ${name} # 例項名稱,這裡複用欄位 name 作為名稱。 subnetName: sls-demo-msn-subnet # 子網的名稱

更多 VPC 的配置內容,檢視 VPC 私有網路 獲取更多詳情資訊。

在子元件的配置檔案中,app 名稱會自動繼承父目錄的 serverless。yml 中的配置。 同時同一個應用的 app 名稱需要保持一致。

2. 新增資料庫

建立子目錄 db 並在子目錄中新增新的 serverless。yml 檔案如下:

component: postgresql #(必填) 引用 component 的名稱,當前用到的是 postgresql 元件name: sls-demo-msn-DB # (必填) 該 postgresql 元件建立的例項名稱inputs: region: ap-guangzhou # 例項所屬地區 zone: ap-guangzhou-2 # 例項所屬地區區域 dBInstanceName: ${name}-${stage} # 資料庫例項名稱唯一,且同一個資料庫只能存在同一個vpc內。 extranetAccess: true # 是否開啟例項外網訪問 vpcConfig: # vpc網路配置 vpcId: ${output:${stage}:${app}:sls-demo-msn-vpc。vpcId} # 私有網路Id subnetId: ${output:${stage}:${app}:sls-demo-msn-vpc。subnetId} # 子網Id

在資料庫配置中新增資料庫到 vpc 網路,這裡使用輸出變數(output)來動態獲取 vpc 的 id 資訊。

更多變數的配置內容,檢視 Serverless 變數 獲取更多詳情資訊。

更多 PostgreSQL 的配置內容,檢視 PostgreSQL 資料庫 獲取更多詳情資訊。

在元件部署完成後,可以在元件目錄內,使用 sls info 檢視元件的輸出變數,或者可以到騰訊雲的應用控制檯檢視相關資訊。

3. 初始化應用目錄

建立子目錄 src 並將建立生成的 index。js (重新命名為todos。js) 和 serverless。yml 移動到目錄中。

在src目錄中執行npm init初始化 Node。js 專案。

在src目錄中執行npm i pg ——save安裝資料庫連結依賴包pg。

在專案根目錄新增根配置檔案serverless。yml,檔案如下:

app: sls-demo-msn-todo-3e5a2134 # 應用唯一識別標識,同賬號下需要保持唯一。stage: dev # 應用部署環境名稱,這裡使用環境變數 STAGE 的值。

根目錄的配置檔案資訊會被子元件繼承,不需要在子元件中重複定義。(僅限於 app 與 stage)。

最終完成的專案目錄結構如下:

。├── README。md├── db # 資料庫│   └── serverless。yml # 資料庫配置檔案├── serverless。yml├── src # 多函式應用│   ├── node_modules│   ├── package-lock。json│   ├── package。json # Node。js依賴檔案│   ├── serverless。yml # 多函式應用配置檔案│   └── todos。js # todo 應用主檔案└── vpc # vpc └── serverless。yml # vpc配置檔案

4. 修改多函式應用配置

在多函式目錄src內修改配置檔案如下:

component: multi-scfname: sls-demo-msninputs: src: src: 。/ exclude: - 。env - “node_modules/**” # 部署時忽略node_modules目錄中所有檔案,以加快部署速度 environments: # 應用環境變數資訊 - key: PG_CONNECT_STRING value: ${output:${stage}:${app}:sls-demo-msn-DB。private。connectionString} region: ap-guangzhou runtime: Nodejs12。16 memorySize: 128 vpc: # vpc網路配置 vpcId: ${output:${stage}:${app}:sls-demo-msn-vpc。vpcId} # 私有網路Id subnetId: ${output:${stage}:${app}:sls-demo-msn-vpc。subnetId} # 子網Id installDependency: true # 是否線上安裝依賴 timeout: 6 # 預設超時時間(秒) functions: # 多函式定義 allTodo: # 函式別名 handler: todos。all # 處理函式 memorySize: 256 # 自定義次函式的記憶體空間 addTodo: handler: todos。add timeout: 9 # 自定義此函式的超時時間(秒) completeTodo: handler: todos。comp timeout: 9 triggers: # 觸發器配置 - type: apigw parameters: name: todosAPIGW protocols: - https - http apis: # API配置 - path: /todos/ # 路由路徑 method: GET # 路由方法 function: allTodo # 路由處理函式別名 - path: /todos/ method: POST function: addTodo - path: /todos/{id}/actions/complete method: POST function: completeTodo param: # 動態路由引數配置 - name: id position: PATH required: true type: number desc: Todo ID

這裡修改主要內容有:

使用installDependency開啟部署後依賴自動安裝並忽略node_module目錄下的全部檔案(無需上傳 node_modules,加快部署)

使用vpc新增 vpc 網路並連結到專案同一個 vpc 網路中。

使用environments新增專案環境變數,並使用輸出變數(output)來動態生成資料庫連線字串。

使用functions來宣告專案中的函式及其別名。

使用triggers宣告函式的觸發器,並在觸發器的apis中配置各個函式對應的路徑,以及引數資訊。

更多函式開發的配置內容和詳情,檢視 PostgreSQL 資料庫 獲取更多詳情資訊。

更多 函式開發 的說明內容,檢視 函式開發 獲取更多詳情資訊。

步驟 4: 開發功能

修改todos。js並完成相關功能的開發,最終該檔案程式碼如下:

“use strict”;const { Client } = require(“pg”);const client = new Client({ connectionString: process。env。PG_CONNECT_STRING,});/** * 初始化資料庫和表結構 */const initDB = async () => { const isConnected = client && client。_connected; if (!isConnected) { await client。connect(); await client。query(` CREATE TABLE IF NOT EXISTS todo ( ID SERIAL NOT NULL, TITLE VARCHAR NOT NULL, NOTE TEXT, IS_COMPLETE BOOLEAN DEFAULT FALSE );`); }};/** * 獲取所有Todo事項 */exports。all = async (event, context) => { // async 需要關閉事件迴圈等待,以避免日誌記錄超時或函式無返回的問題。 context。callbackWaitsForEmptyEventLoop = false; await initDB(); const { rows } = await client。query({ text: “SELECT * FROM todo” }); return { message: “Tencent SCF execute successful!”, data: rows, };};/** * 新增新的Todo事項 */exports。add = async (event, context) => { // async 需要關閉事件迴圈等待,以避免日誌記錄超時或函式無返回的問題。 context。callbackWaitsForEmptyEventLoop = false; const { title, note } = JSON。parse(event。body); if (!title) { return { statusCode: 400, message: “Missing Todo Title”, }; } await initDB(); const { rowCount } = await client。query({ text: “INSERT INTO todo (title, note) VALUES($1, $2)”, values: [title, note], }); return rowCount === 1 ? { statusCode: 201, message: “Todo added success。”, } : { statusCode: 400, message: “Todo added failed。”, };};/** * 完成指定Todo事項 */exports。comp = async (event, context) => { // async 需要關閉事件迴圈等待,以避免日誌記錄超時或函式無返回的問題。 context。callbackWaitsForEmptyEventLoop = false; const todoId = event。pathParameters。id; if (!todoId && !isNaN(todoId)) { return { statusCode: 400, message: “Missing Todo Id”, }; } await initDB(); const { rowCount } = await client。query({ text: “UPDATE todo SET is_complete = true WHERE id=$1”, values: [todoId], }); return rowCount === 1 ? { statusCode: 200, message: “Todo Complete success。”, } : { statusCode: 400, message: “Todo Complete failed。”, };};

步驟 5: 除錯功能

1. Invoke 除錯

要除錯程式碼除了使用第三方開發工具透過配置的 API 閘道器 url 除錯,還可以使用 Serverless Framework 的 Invoke 功能 或 遠端除錯 功能。 這裡使用 invoke 功能演示如何除錯函式功能。

invoke 和 遠端除錯功能 需要在元件的目錄內執行。

2. 獲取全部 Todo

在 src 目錄下執行

$ serverless invoke -f allTodo

執行後可以得到的結果

使用授權資訊 default 授權中,如果需要使用臨時金鑰,請使用 ——login 重新登陸billDuration: 36duration: 36errMsg:functionRequestId: fe6d302d-f6db-42ad-9c7b-8d0c61ead9b3invokeResult: 0log: “”“ START RequestId: fe6d302d-f6db-42ad-9c7b-8d0c61ead9b3 Event RequestId: fe6d302d-f6db-42ad-9c7b-8d0c61ead9b3 END RequestId: fe6d302d-f6db-42ad-9c7b-8d0c61ead9b3 Report RequestId: fe6d302d-f6db-42ad-9c7b-8d0c61ead9b3 Duration:36ms Memory:256MB MemUsage:11。3984MB ”“”memUsage: 11952128——————————————————————-Serverless: 呼叫成功{ message: ‘Tencent SCF execute successful!’, data: []}

在 invoke 返回的結果中,會包含函式執行後的 meta 資訊,如執行時間,錯誤,RequestId,執行的日誌 和函式返回的結果。

3. 建立新的 Todo

在 src 目錄下執行

$ serverless invoke -f addTodo ——data “{\”body\“:\”{\\\“title\\\”:\\\“Create multi-scf project demo\\\”,\\\“note\\\”:\\\“Todo App with postgreSQL\\\”}\“}”

執行後可以得到的結果

使用授權資訊 default 授權中,如果需要使用臨時金鑰,請使用 ——login 重新登陸billDuration: 35duration: 35errMsg:functionRequestId: 93f50016-064f-468d-9e98-31645fc254fdinvokeResult: 0log: “”“ START RequestId: 93f50016-064f-468d-9e98-31645fc254fd Event RequestId: 93f50016-064f-468d-9e98-31645fc254fd END RequestId: 93f50016-064f-468d-9e98-31645fc254fd Report RequestId: 93f50016-064f-468d-9e98-31645fc254fd Duration:35ms Memory:128MB MemUsage:11。293MB ”“”memUsage: 11841536——————————————————————-Serverless: 呼叫成功{ statusCode: 201, message: ‘Todo added success。’}

步驟 6:部署和日誌

1. 部署程式碼到生產環境

使用下面命令可以快速部署專案到生產環境(這裡命名生產環境為prod)

$ serverless deploy ——stage prod

2. 即時檢視生產環境日誌

在專案目錄src中執行以下命令可以檢視專案的即時日誌資訊

$ sls logs ——tail -f allTodo ——stage prod

以下是返回結果:

使用授權資訊 default 授權中,如果需要使用臨時金鑰,請使用 ——login 重新登陸serverless ⚡componentsAction: “logs” - Stage: “prod” - App: “sls-demo-msn-todo-3e5a2134” - Name: “sls-demo-msn”START RequestId:6f31857109130f092c547337c073ea91Response RequestId:dbb3a8ed63a32be8e6b7a2dd8a32bbe2 RetMsg:{“message”:“Tencent SCF execute successful!”,“data”:[{“id”:1,“title”:“Create multi-scf project demo”,“note”:“Todo App with postgreSQL”,“is_complete”:false}]}END RequestId:dbb3a8ed63a32be8e6b7a2dd8a32bbe2Report RequestId:dbb3a8ed63a32be8e6b7a2dd8a32bbe2 Duration:4ms Memory:256MB MemUsage:12。113281MBResponse RequestId:485a87cfc6ad385b7e9c84343962391b RetMsg:{“message”:“Tencent SCF execute successful!”,“data”:[{“id”:1,“title”:“Create multi-scf project demo”,“note”:“Todo App with postgreSQL”,“is_complete”:false}]}END RequestId:485a87cfc6ad385b7e9c84343962391bReport RequestId:485a87cfc6ad385b7e9c84343962391b Duration:4ms Memory:256MB MemUsage:11。886719MBSTART RequestId:0ede6d26dca55362a701c10ff51c9021Serverless › 監聽中 。。。

總結

感謝長久以來對 Serverless Framework 支援的廣大開發者,未來我們也會繼續迭代產品,推出新功能,改進產品使用體驗,最終我們會為中國的開發者打造一套符合中國開發者習慣的無伺服器開發的完整解決方案。

也歡迎大家到 Serverless 中文社群分享經驗和想法以及反饋問題和 BUG。

Serverless 中文社群:https://github。com/serverless/serverless-tencent/discussions

最後希望大家可以參與我們的有獎調查問卷:https://www。surveymonkey。com/r/blog-msntodo

One More Thing

立即體驗騰訊雲 Serverless Demo,領取 Serverless 新使用者禮包 騰訊雲 Serverless 新手體驗

歡迎訪問:Serverless 中文網!