設計實現SAM--無伺服器應用模型

心譚小站發表於2020-08-04

Author:心譚
From:【Serverless】設計實現SAM--無伺服器應用模型
Des: 專注演算法與 web 開發的技術部落格

什麼是SAM?

sam全稱是:Serverless Application Model,也就是無伺服器應用模型。

它使用yaml語法來描述一個應用程式,服務商會對.yml字尾的sam檔案進行解析,並按照檔案描述部署相關服務。

應用場景

SAM的概念最初由AWS提出,用來描述程式所需要的Lambda function、Cloud DB等雲端資源。

騰訊云云開發的擴充套件能力中,也使用SAM來描述擴充套件能力所需要的雲開發資源,包括雲函式、儲存、資料庫,甚至其他的雲能力,例如簡訊傳送。簡訊驗證碼登入 本身就是擴充套件,用到了騰訊雲的簡訊能力。

再發揮一下,sam可以用來描述簡單的UI檢視,尤其適合表單的應用場景,如下所示:

實現簡易的SAM

定義SAM

因為sam是yaml語法檔案,所以需要解析yaml語法,使用yaml.js

舉個例子,某個程式需要使用到雲函式,並且需要建立兩個資料表,SAM檔案如下:

ApplicationName: 測試程式

# 雲函式資源
Function:
    # 執行環境
    Container: nodejs 8.9
    # 超時時間(秒)
    Timeout: 60 
    Corn: 

# 雲資料庫資源
Database:
    # 需要建立的資料集合
    Collections: 
        -
            CollectionName: 'ext-collection-a'
        -
            CollectionName: 'ext-collection-b'

資料校驗

由於前端輸入的資料不可信,後端需要對傳入的SAM進行校驗。

隨著依賴的資源欄位增加,單純使用 if-else 的邏輯判斷,會讓程式碼變得難以維護,可讀性非常差。

通常有2種資料校驗的思路:

  • 藉助 joi.js,在程式碼中增加校驗邏輯
  • 使用 ajv.js,分離Schema和程式碼邏輯

第2種思路耦合度更低,並且規則的改動和維護,不涉及程式碼改動,產品和運營同學也可以來維護規則

按照schema的ajv語法,以前面的SAM檔案為例,schema 的內容如下:

{
    "type": "object",
    "properties": {
        "ApplicationName": {
            "type": "string"
        },
        "Function": {
            "type": "object",
            "required": ["Container", "Timeout"],
            "properties": {
                "Container": {
                    "type": "string"
                },
                "Timeout": {
                    "type": "number"
                },
                "Corn": {
                    "type": ["string", "null"]
                }
            }
        },
        "Database": {
            "type": "object",
            "Collections": {
                "type": "array",
                "items": {
                    "properties": {
                        "CollectionName": {
                            "type": "string"
                        }
                    }
                }
            }
        }
    }
}

封裝ajv的驗證邏輯:

const Ajv = require('ajv')
/**
 * 驗證obj是否符合 Schema 定義
 * @param {object} obj
 * @param {string} schemaJson 
 * @return {boolean}
 */
function validateSchema(obj, schemaFilePath) {
    const schemaJson = require(schemaFilePath)
    
    const ajv = new Ajv()
    const validate = ajv.compile(schemaJson)
    const valid = validate(obj)
    if (!valid) {
        console.log('>>> 錯誤欄位資訊:', validate.errors)
    }
    return valid
}

變數注入

有些時候,某些變數是動態的。例如,使用者資訊可能在執行過程中被注入到上下文,資料集合名稱需要前端使用者表單傳入。

舉個例子,前面建立的兩個資料集合的名稱由前端表單傳入,對應欄位是:collectionNameAcollectionNameB

# 雲資料庫資源
Database:
    # 需要建立的資料集合
    Collections: 
        -
            CollectionName: '${env.collectionNameA}'
        -
            CollectionName: '${env.collectionNameB}'

整個流程總結:

  • 服務端解析預設的SAM配置
  • 識別${}特殊字串,替換變數
  • 驗證是否符合Schema定義的規則

參考連結

相關文章