天天看點

AWS的Serverless(Lambda)實踐

(一)Lambda功能介紹

AWS Step Functions 将多個AWS服務協調為無伺服器工作流,以便可以快速建構和更新應用程式。使用Step Functions,可以設計和運作将AWS Lambda 和 Amazon ECS等服務整合到功能豐富的應用程式中的工作流。工作流由一系列步驟組成,一個步驟的輸出充當下一個步驟的輸入。 使用Step Functions,應用程式開發更簡單、更直覺,因為它将工作流轉換為易于了解、易于向其他人說明且易于更改的狀态機示意圖。可以監控執行的每個步驟,這意味着可以快速識别并解決問題。 Step Functions可以自動觸發和跟蹤各個步驟,并在出現錯誤時重試,是以的應用程式能夠按照預期順序執行。

(二)demo實踐

為了友善大家了解AWS Step Functions,以下我們将通過一個實際案例的動手操作,來幫忙大家了解AWS Step Functions,以及AWS SNS/AWS Dynamodb等服務。測試Demo架構如下:

AWS的Serverless(Lambda)實踐

2.1 AWS Step Function 狀态機的工作流程

2.1.1工作流如圖所示:

2.1.2工作流描述:

1)調用 Input Lottery Winners 函數,傳入 num_of_winners,進入第二步。

2)Random Select Winners 根據 Input Lottery Winners 的輸出(body)調用 Random Select Winners,生成兩個獲獎号碼,進入第三步。

3)Validate Winners 根據第二步輸出查詢 Winners 表判斷是否重複,重複則傳出 status:1,否則傳出 status:0。

4)Is Winner In Past Draw 接受第三步 status 并判斷,當 status 為1,則重新調用 Random Select Winners 進入第二步,當 status 為0,則調用 Notify Winners 和 Record Winner Queue,給 5)SNS topic 發送通知,把獲獎者寫入 Winner 表。

在整個工作流程中,當 Catch 接收到錯誤,都直接進入 Failed 步驟,輸出異常并中斷 step function。

2.2 建立過程及步驟

2.2.1 建立IAM角色

執行 lambda的角色需要以下政策:

AmazonDynamoDBFullAccess

AWSLambdaBasicExecutionRole

AmazonSNSFullAccess

AWSStepFunctionsFullAccess

在AWS的Console建立角色的過程如下:

2.2.2建立Lambda

Input Lottery Winners

為了實作Step Functions狀态機流轉下的任務,我們這次實作會用到AWS Lambda作為我們業務的實作環境

1)進入AWS控制台,選擇服務然後輸入Lambda進入AWS Lambda控制台

2)選擇建立函數,然後選擇從頭開始創作來自定義我們的實驗程式

3)首先我們需要建立狀态機中的第一個狀态任務Input Lottery Winners,輸入函數名稱Lottery-InputWinners來定義幸運兒的數量。運作語言選擇Python 3.7。同時需要選擇函數執行的權限,

這裡我們選擇使用現有角色,選擇之前建立的IAM角色

4)點選建立函數

5)在函數代碼欄目下輸入如下代碼塊,修改代碼中的 region_name為目前使用的AWS的region

6)建立函數時複制頁面右上角的ARN,為後面建立狀态機準備

為Lottery-InputWinners函數準備代碼塊如下:

import json

class CustomError(Exception):

    pass

def lambda_handler(event, context):

    num_of_winners = event['input']

    # Trigger the Failed process

    if 'exception' in event:

        raise CustomError("An error occurred!!")

    return {

        "body": {

            "num_of_winners": num_of_winners

        }

    }           

接下來我們還需要建立另外三個需要定義的狀态機業務邏輯,建立過程和上面的Lottery-InputWinners函數一緻,下面是具體的狀态機的代碼塊

Lottery-RandomSelectWinners的函數代碼塊:

import json
import boto3
from random import randint
from boto3.dynamodb.conditions import Key, Attr

TOTAL_NUM = 10

def lambda_handler(event, context):

    # variables

    num_of_winners = event['num_of_winners']

    # query in dynamodb

    dynamodb = boto3.resource('dynamodb', region_name='')

    table = dynamodb.Table('Lottery-Employee')

    # random select the winners, if has duplicate value, re-run the process

    while True:

        lottery_serials = [randint(1,TOTAL_NUM) for i in range(num_of_winners)]

        if len(lottery_serials) == len(set(lottery_serials)):

            break

    # retrieve the employee details from dynamodb

    results = [table.query(KeyConditionExpression=Key('lottery_serial').eq(serial), IndexName='lottery_serial-index') for serial in lottery_serials]

    # format results

    winner_details = [result['Items'][0] for result in results]

    return {

        "body": {

            "num_of_winners": num_of_winners,

            "winner_details": winner_details

        }

    }           

Lottery-ValidateWinners的函數代碼塊:

import json
import boto3
from boto3.dynamodb.conditions import Key, Attr

def lambda_handler(event, context):

    # variables

    num_of_winners = event['num_of_winners']

    winner_details = event['winner_details']

    # query in dynamodb

    dynamodb = boto3.resource('dynamodb', region_name='')

    table = dynamodb.Table('Lottery-Winners')

    # valiate whether the winner has already been selected in the past draw

    winners_employee_id = [winner['employee_id'] for winner in winner_details]

    results = [table.query(KeyConditionExpression=Key('employee_id').eq(employee_id)) for employee_id in winners_employee_id]

    output = [result['Items'] for result in results if result['Count'] > 0]

    # if winner is in the past draw, return 0 else return 1

    has_winner_in_queue = 1 if len(output) > 0 else 0

    # format the winner details in sns

    winner_names = [winner['employee_name'] for winner in winner_details]

    name_s = ""

    for name in winner_names:

        name_s += name

        name_s += " "

    return {

        "body": {

            "num_of_winners": num_of_winners,

            "winner_details": winner_details

        },

        "status": has_winner_in_queue,

        "sns": "Congrats! [{}] You have selected as the Lucky Champ!".format(name_s.strip())

    }
           

Lottery-RecordWinners函數代碼塊:

import json
import boto3
from boto3.dynamodb.conditions import Key, Attr

def lambda_handler(event, context):

    # variables

    winner_details = event['winner_details']

    # retrieve the winners' employee id

    employee_ids = [winner['employee_id'] for winner in winner_details]

    # save the records in dynamodb

    dynamodb = boto3.resource('dynamodb', region_name='')

    table = dynamodb.Table('Lottery-Winners')

    for employee_id in employee_ids:

        table.put_item(Item={

            'employee_id': employee_id

        }) 

    return {

        "body": {

            "winners": winner_details

        },

        "status_code": "SUCCESS" 

    }           

2.2.3建立SNS通知服務

1)進入AWS控制台,在服務中搜尋SNS

2)在SNS控制台中,選擇主題, 然後選擇建立主題

3)在建立新主題彈框中,輸入如下内容:

  • 主題名稱: Lottery-Notification
  • 顯示名稱: Lottery

1)建立主題後,會進入主題詳細資訊頁面,這時候我們需要建立訂閱來對接我們的消息服務,例如郵件服務(本次實驗使用郵件服務來作為消息服務)

2)點選建立訂閱, 在彈框中選擇

  • 協定: Email
  • 終端節點: <填入自己的郵箱位址>

1)點選請求确認, 然後到上面填寫的郵箱位址中确認收到資訊,表示确認該郵箱可以接收來自AWS SNS該主題的通知消息

2)複制主題詳細頁面的主題ARN,之後替換Step Functions狀态機下的<Notification:ARN>

2.2.4建立Amazon Dynamodb服務

本次實驗需要建立兩張Dynamodb表來記錄員工資訊和幸運兒資訊。使用Dynamodb能更快地通過托管的方式記錄資料同時免去資料庫運維的壓力。

1)進入AWS控制台,在服務中搜尋Dynamodb

2)在左側控制欄中選在表, 然後在首頁面中選擇建立表

3)在建立Dynamodb表中,填入如下資訊

  • 表名稱:Lottery-Winners
  • 主鍵:employee_id

1)表設定中确認勾選使用預設設定,點選建立

2)同樣的設定步驟,點選建立表,在建立Dynamodb表中,填入如下資訊

  • 表名稱:Lottery-Employee

2)等待表建立完成後, 通過本附件中的request-items.json檔案導入資料到Lottery-Employee

$ aws dynamodb batch-write-item --request-items file://request-items.json

1)選擇表Lottery-Employee Tab頁面中的索引, 點選建立索引

  • 主鍵:lottery_serial, 字段類型選擇數字
  • 索引名稱:lottery_serial-index

2.2.5建立AWS Step Functions 狀态機

1)進入AWS控制台,在服務中搜尋Step Functions

2)進入Step Functions服務後,點選左側的活動欄,并點選狀态機

3)進入狀态機首頁面後,選擇建立狀态機

4)在定義狀态機欄目下,選擇預設使用代碼段創作。同時在詳細資訊欄目輸入狀态機名稱:Lottery

5)在狀态機定義欄目下,複制如下狀态機定義檔案,通過Amazon States Language來定義狀态機的狀态流轉

狀态機名稱:Lottery

{

"Comment": "A simple AWS Step Functions state machine that simulates the lottery session",

  "StartAt": "Input Lottery Winners",

  "States": {

    "Input Lottery Winners": {

        "Type": "Task",

        "Resource": "<InputWinners:ARN>",

        "ResultPath": "$",

        "Catch": [ 

            {          

              "ErrorEquals": [ "CustomError" ],

              "Next": "Failed"      

            },

            {          

              "ErrorEquals": [ "States.ALL" ],

              "Next": "Failed"      

            } 

          ],

        "Next": "Random Select Winners"

    }, 

    "Random Select Winners": {

      "Type": "Task",

      "InputPath": "$.body",

      "Resource": "<RandomSelectWinners:ARN>",

      "Catch": [ 

        {          

          "ErrorEquals": [ "States.ALL" ],

          "Next": "Failed"      

        } 

      ],      

     "Retry": [ 

        {

          "ErrorEquals": [ "States.ALL"],          

          "IntervalSeconds": 1, 

          "MaxAttempts": 2

        } 

      ],

      "Next": "Validate Winners"

    },

    "Validate Winners": {

      "Type": "Task",

      "InputPath": "$.body",

      "Resource": "<ValidateWinners:ARN>",

      "Catch": [ 

        {          

          "ErrorEquals": [ "States.ALL" ],

          "Next": "Failed"      

        } 

      ],      

     "Retry": [ 

        {

          "ErrorEquals": [ "States.ALL"],          

          "IntervalSeconds": 1, 

          "MaxAttempts": 2

        } 

      ],

      "Next": "Is Winner In Past Draw"

    },

    "Is Winner In Past Draw": {

      "Type" : "Choice",

        "Choices": [

          {

            "Variable": "$.status",

            "NumericEquals": 0,

            "Next": "Send SNS and Record In Dynamodb"

          },

          {

            "Variable": "$.status",

            "NumericEquals": 1,

            "Next": "Random Select Winners"

          }

      ]

    },

    "Send SNS and Record In Dynamodb": {

      "Type": "Parallel",

      "End": true,

      "Catch": [ 

        {          

          "ErrorEquals": [ "States.ALL" ],

          "Next": "Failed"      

        } 

      ],      

     "Retry": [ 

        {

          "ErrorEquals": [ "States.ALL"],          

          "IntervalSeconds": 1, 

          "MaxAttempts": 2

        } 

      ],

      "Branches": [

        {

         "StartAt": "Notify Winners",

         "States": {

           "Notify Winners": {

             "Type": "Task",

             "Resource": "arn:aws:states:::sns:publish",

             "Parameters": {

               "TopicArn": "<Notification:ARN>",

               "Message.$": "$.sns"

             },

             "End": true

           }

         }

       },

       {

         "StartAt": "Record Winner Queue",

         "States": {

           "Record Winner Queue": {

             "Type": "Task",

             "InputPath": "$.body",

             "Resource":

               "<RecordWinners:ARN>",

             "TimeoutSeconds": 300,

             "End": true

           }

         }

       }

      ]

    },

    "Failed": {

        "Type": "Fail"

     }

  }

}           

1)在狀态機定義欄目的右側,點選重新整理按鈕,可以看到狀态機流轉的流程圖。使用之前的 lambda ARN(4個),SNS topic ARN(1個),對應替換狀态機 json 檔案中的 <InputWinners:ARN>,<RandomSelectWinners:ARN>,<ValidateWinners:ARN>,<RecordWinners:ARN>,<Notification:ARN>,點選下一步。

2)在配置設定下,選擇為我建立IAM角色, 輸入自定義的IAM角色名稱MyStepFunctionsExecutionRole,并且附加AmazonSNSFullAccess權限

3)點選建立狀态機完成建立過程

(三)執行 Step Function 狀态機

1)入AWS控制台,在服務中搜尋Step Functions

2)進入之前建立的狀态機Lottery

3)點選啟動執行

4)在彈框中填入輸入的json 文本,這裡的input代表在本次實驗中需要抽取的獲獎人數

{

    "input": 2

}           

5)點選啟動執行

(四) 實驗結果

1)Dynamodb表中Lottery-Winners記錄獲獎者

2)郵件會收取到辛運兒的資訊

(五)總結描述

繼續閱讀