在雲端架構中,訊息傳遞和通知扮演著至關重要的角色。本文將示範如何利用 AWS Lambda、SNS 和 SQS 構建一個高效的訊息處理系統。首先,我們會使用 CloudFormation 建立 SNS 主題,並透過 AWS CLI 建立 SMS 和 Email 訂閱。接著,我們將探討如何使用 Java SDK 在 Lambda 函式中釋出訊息到 SNS 主題,並示範如何使用 AWS CLI 佈署和測試 Lambda 函式。最後,我們將介紹如何使用 SNS 事件觸發 Lambda 函式,並提供完整的程式碼範例和逐步操作。此架構能讓開發者更有效率地處理訊息,並確保訊息的可靠傳遞和通知。

使用 SQS 和 SNS 進行訊息傳遞和通知(第六章)

建立 SNS 主題與訂閱

在前面的章節中,我們已經瞭解瞭如何使用 AWS CLI 和 CloudFormation 建立 SNS 主題。本文將探討如何建立 SNS 主題、建立訂閱以及發布訊息至該主題。

使用 CloudFormation 建立 SNS 主題

以下是一個 CloudFormation 範本,用於建立 SNS 主題並輸出其 ARN 和名稱:

Resources:
  SNSTopic:
    Type: 'AWS::SNS::Topic'
    Properties:
      TopicName: !Sub 'my-first-sns-topic-${AWS::Region}'

Outputs:
  SNSTopicARN:
    Value: !Ref SNSTopic
    Export:
      Name: "SNSTopicARN"
  SNSTopicName:
    Value: !GetAtt SNSTopic.TopicName
    Export:
      Name: "SNSTopicName"

此範本建立了一個 SNS 主題,並將其 ARN 和名稱作為輸出,以便在其他堆積疊中使用。

建立 SMS 和電子郵件訂閱

使用 AWS CLI 可以建立 SMS 和電子郵件訂閱,如下所示:

SMS 訂閱
aws sns subscribe \
--topic-arn arn:aws:sns:us-east-1:<account id>:my-first-sns-topic \
--protocol sms \
--notification-endpoint +917411174114 \
--profile admin

此命令建立了一個 SMS 訂閱,將訊息傳送至指定的手機號碼。

電子郵件訂閱
aws sns subscribe \
--topic-arn arn:aws:sns:us-east-1:<account id>:my-first-sns-topic \
--protocol email \
--notification-endpoint serverlesscookbook@gmail.com \
--profile admin

此命令建立了一個電子郵件訂閱,將訊息傳送至指定的電子郵件地址。

發布訊息至 SNS 主題

使用以下命令可以發布訊息至 SNS 主題:

aws sns publish \
--topic-arn arn:aws:sns:us-east-1:<account id>:my-first-sns-topic \
--message "sending message to both mobile and email" \
--profile admin

此命令發布了一則訊息至 SNS 主題,該訊息將被傳送至所有訂閱者。

使用 Java SDK 發布訊息至 SNS 主題

在前面的章節中,我們瞭解瞭如何使用 AWS CLI 發布訊息至 SNS 主題。本文將介紹如何使用 Java SDK 發布訊息至 SNS 主題。

Lambda 專案程式碼(Java)

首先,建立一個 Java Lambda 專案,並在 pom.xml 檔案中新增以下相依性:

<dependency>
  <groupId>com.amazonaws</groupId>
  <artifactId>aws-java-sdk-sns</artifactId>
  <version>${aws.sdk.version}</version>
</dependency>

接下來,建立一個 Request 類別,用於接收輸入 JSON:

@Data
public class Request {
  private String topicArn;
  private String message;
}

然後,建立一個 LambdaSnsPublishHandler 類別,用於處理 Lambda 請求:

public class LambdaSnsPublishHandler {
  private final AmazonSNS snsClient;

  public LambdaSnsPublishHandler() {
    this.snsClient = AmazonSNSClientBuilder.standard()
        .withRegion(System.getenv("AWS_REGION"))
        .build();
  }

  public String handleRequest(final Request request, final Context context) {
    final PublishResult result;
    try {
      PublishRequest publishRequest = new PublishRequest(request.getTopicArn(), request.getMessage());
      result = snsClient.publish(publishRequest);
    } catch (Exception e) {
      return "Exception occurred: " + e.getMessage();
    }
    // ...
  }
}

在此範例中,我們使用 AmazonSNSClientBuilder 建立了一個 SNS 使用者端,並使用 publish 方法發布訊息至 SNS 主題。

程式碼解析

  1. 建立 SNS 使用者端:使用 AmazonSNSClientBuilder 建立了一個 SNS 使用者端,並設定了區域。
  2. 發布訊息:使用 publish 方法發布訊息至 SNS 主題,並傳遞了 PublishRequest 物件。
  3. 錯誤處理:捕捉了例外狀況,並傳回錯誤訊息。

使用 SQS 和 SNS 進行訊息傳遞與通知(第六章)

使用 Java SDK 釋出訊息至 SNS 主題

本章節將介紹如何使用 Java SDK 在 Lambda 函式中釋出訊息至 SNS 主題。首先,我們需要建立一個 Java Lambda 專案,並在 pom.xml 檔案中加入 AWS Java SDK 的依賴。

Lambda 專案程式碼(Java)

public class LambdaSnsPublishHandler {
    public String handleRequest(Map<String, String> input, Context context) {
        // 初始化 SNS Client
        AmazonSNS snsClient = AmazonSNSClientBuilder.standard()
                .withRegion(System.getenv("AWS_REGION"))
                .build();

        // 釋出訊息至 SNS 主題
        PublishRequest publishRequest = new PublishRequest(
                input.get("topicArn"),
                input.get("message")
        );
        PublishResult result = snsClient.publish(publishRequest);

        // 傳回訊息 ID
        return "Message Id: " + result.getMessageId();
    }
}

內容解密:

  1. 初始化 SNS Client:使用 AmazonSNSClientBuilder 建立 SNS Client,並指定 AWS 區域。
  2. 釋出訊息至 SNS 主題:建立 PublishRequest 物件,指定 SNS 主題的 ARN 和要釋出的訊息。
  3. 傳回訊息 ID:釋出訊息後,傳回訊息的 ID。

使用 AWS CLI 佈署和測試 Lambda 函式

步驟如下:

  1. 封裝 Lambda 專案:執行 mvn clean package 命令,將專案封裝成 Uber JAR。
  2. 上傳 Uber JAR 至 S3:使用 AWS CLI 將 Uber JAR 上傳至 S3 Bucket。
aws s3 cp target/lambda-sns-publish-with-sdk-0.0.1-SNAPSHOT.jar s3://serverless-cookbook/lambda-sns-publish-with-sdk-0.0.1-SNAPSHOT.jar --profile admin
  1. 建立 Lambda 執行角色:建立一個 IAM 角色,並附加必要的許可權。
  2. 建立 Lambda 函式:使用 AWS CLI 建立 Lambda 函式,並指定執行角色和處理程式。
aws lambda create-function --function-name lambda-sns-publish-with-sdk --runtime java8 --role arn:aws:iam::855923912133:role/lambda-sns-publish-with-sdk-role --handler tech.heartin.books.serverlesscookbook.LambdaSnsPublishHandler::handleRequest --code S3Bucket=serverless-cookbook,S3Key=lambda-sns-publish-with-sdk-0.0.1-SNAPSHOT.jar --timeout 15 --memory-size 512 --region us-east-1 --profile admin
  1. 測試 Lambda 函式:使用 AWS CLI 呼叫 Lambda 函式,並傳遞測試資料。
aws lambda invoke --invocation-type RequestResponse --function-name lambda-sns-publish-with-sdk --log-type Tail --payload file://payload.json --region us-east-1 --profile admin outputfile.txt

內容解密:

  1. 封裝和上傳 Lambda 專案:將專案封裝成 Uber JAR,並上傳至 S3 Bucket。
  2. 建立和組態 Lambda 函式:建立 Lambda 函式,並指定執行角色、處理程式和必要的組態。
  3. 測試 Lambda 函式:呼叫 Lambda 函式,並驗證其是否正確執行。

使用 SNS 事件呼叫 Lambda 函式(Java)

本章節將介紹如何使用 SNS 事件呼叫 Lambda 函式。首先,我們需要建立一個 Java Lambda 專案,並在 pom.xml 檔案中加入 AWS Java SDK 的依賴。

Lambda 專案程式碼(Java)

public class LambdaSnsEventHandler {
    private final AmazonSQS sqsClient;

    public LambdaSnsEventHandler() {
        this.sqsClient = AmazonSQSClientBuilder.standard()
                .withRegion(System.getenv("AWS_REGION"))
                .build();
    }

    public Boolean handleRequest(final SNSEvent snsEvent, final Context context) {
        context.getLogger().log("Received SQS event: " + snsEvent);
        final SnsService snsService = new SnsServiceImpl(this.sqsClient);
        return snsService.processEvent(snsEvent, System.getenv("SPC_OUTPUT_QUEUE_URL"), context.getLogger());
    }
}

內容解密:

  1. 初始化 SQS Client:使用 AmazonSQSClientBuilder 建立 SQS Client,並指定 AWS 區域。
  2. 處理 SNS 事件:建立 SnsService 物件,並呼叫其 processEvent 方法處理 SNS 事件。
  3. 傳回處理結果:傳回處理結果的布林值。

使用 SQS 和 SNS 進行訊息傳遞與通知(第六章)

使用 AWS CLI 組態 Lambda

要佈署並呼叫 Lambda,請按照以下步驟進行:

  1. 建立 Uber JAR 檔案:在 Lambda 專案的根資料夾中執行 mvn clean package 以建立 Uber JAR。

  2. 將 Uber JAR 上傳到 S3

    aws s3 cp \
    target/lambda-invoke-sns-event-0.0.1-SNAPSHOT.jar \
    s3://serverless-cookbook/lambda-invoke-sns-event-0.0.1-SNAPSHOT.jar \
    --profile admin
    
  3. 為 Lambda 建立角色:使用適當的信任關係定義建立角色。

    aws iam create-role \
    --role-name lambda-invoke-sns-event-role \
    --assume-role-policy-document file://iam-role-trust-relationship.txt \
    --profile admin
    
  4. 建立基本日誌記錄許可權的策略並將其附加到角色

  5. 建立所需的 SQS 許可權策略並將其附加到角色。所需的 SQS 許可權策略如下:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "sqs:SendMessage",
            "sqs:SendMessageBatch"
          ],
          "Resource": [
            "arn:aws:sqs:*:*:*"
          ]
        }
      ]
    }
    

    內容解密:

    • 此策略允許 Lambda 向 SQS 佇列傳送訊息。
    • sqs:SendMessagesqs:SendMessageBatch 是必要的動作,因為 Lambda 需要將接收到的訊息寫入佇列。
  6. 建立 Lambda 函式

    aws lambda create-function \
    --function-name lambda-invoke-sns-event \
    --runtime java8 \
    --role arn:aws:iam::<account id>:role/lambda-invoke-sns-event-role \
    --handler tech.heartin.books.serverlesscookbook.LambdaSnsEventHandler::handleRequest \
    --code S3Bucket=serverless-cookbook,S3Key=lambda-invoke-sns-event-0.0.1-SNAPSHOT.jar \
    --environment Variables={SPC_OUTPUT_QUEUE_URL='https://queue.amazonaws.com/855923912133/my-output-queue'} \
    --timeout 15 \
    --memory-size 512 \
    --region us-east-1 \
    --profile admin
    

    內容解密:

    • 此命令建立了一個名為 lambda-invoke-sns-event 的 Lambda 函式。
    • 指定了執行角色、處理程式、程式碼位置、環境變數、超時和記憶體大小。
  7. 將 Lambda 訂閱到佇列

    aws sns subscribe --topic-arn arn:aws:sns:us-east-1:<account id>:lambda-invoke-sns-topic \
    --protocol lambda \
    --notification-endpoint arn:aws:lambda:us-east-1:<account id>:function:lambda-invoke-sns-event \
    --profile admin
    

    內容解密:

    • 此命令將 Lambda 函式訂閱到指定的 SNS 主題。

測試 Lambda(使用 AWS CLI)

  1. 向主題傳送訊息
  2. 透過從輸出佇列檢索訊息來驗證呼叫
    aws sqs receive-message \
    --queue-url https://queue.amazonaws.com/<account id>/my-output-queue \
    --max-number-of-messages 5 \
    --profile admin
    

    內容解密:

    • 此命令從指定的 SQS 佇列接收訊息,以驗證 Lambda 函式是否正確處理了 SNS 事件。

更多資訊

SNS 可以將訊息扇出到多個 SQS 佇列,用於平行處理等場景。這種模式通常被稱為扇出模式。