谈谈AWS 的 SNS SQS Lambda分别是什么

AWS(Amazon Web Services) 提供了一系列的云计算服务,其中 SNS (Simple Notification Service)、SQS (Simple Queue Service) 和 Lambda 是其中的三项核心服务

SNS (Simple Notification Service)

  • 定义: SNS 是一项用于构建分布式系统中发布/订阅模式的服务。它允许发布者(发布消息的服务或应用程序)将消息发送到一个主题,而订阅者(接收消息的服务或应用程序)可以订阅这些主题以接收消息。
  • 使用场景: 适用于需要在多个组件或服务之间进行异步通信的场景。常见的用例包括通知、事件处理等。

SQS (Simple Queue Service):

  • 定义: SQS 是一项托管的消息队列服务,用于通过分离消息的生产者和消费者来实现分布式系统的解耦。消息在队列中存储,等待被消费者处理。
  • 使用场景: 适用于构建分布式系统,其中不同的组件需要以异步方式进行通信,并且希望实现松耦合。可以用于削峰填谷、任务分发等场景。

Lambda:

  • 定义: Lambda 是一项无服务器计算服务,允许您运行代码而无需管理服务器。您只需上传代码并定义触发器,当触发条件满足时,AWS Lambda 将自动执行您的代码。
  • 使用场景: 适用于事件驱动的计算,可以在需要时执行代码,而无需一直保持服务器运行。常见用例包括数据处理、图像处理、API 执行等。

这三项服务通常可以协同工作,例如,您可以使用 SNS 将消息发布到主题,然后通过 SQS 将这些消息传递到队列,最后通过 Lambda 处理队列中的消息。这样的组合提供了灵活性和可扩展性,适用于各种云计算场景

下面来分别说明:

以下用nestjs框架来说明

SNS

import {
    
     Injectable } from '@nestjs/common';
import * as AWS from 'aws-sdk';

@Injectable()
export class NotificationService {
    
    
  private readonly sns: AWS.SNS;
  private topicArn: string;

  constructor() {
    
    
    // 初始化 AWS SNS 实例
    this.sns = new AWS.SNS();
    AWS.config.update({
    
     region: 'your-region' }); // 替换为您的 AWS 区域
  }

  // 创建 SNS 主题
  async createTopic(topicName: string): Promise<void> {
    
    
    const topicParams: AWS.SNS.CreateTopicInput = {
    
    
      Name: topicName,
    };

    const result = await this.sns.createTopic(topicParams).promise();
    this.topicArn = result.TopicArn;
    console.log(`Topic created with ARN: ${
      
      this.topicArn}`);
  }

  // 发布消息到已创建的主题
  async publishMessage(message: string): Promise<void> {
    
    
    if (!this.topicArn) {
    
    
      throw new Error('Topic not created. Call createTopic() first.');
    }

    const publishParams: AWS.SNS.PublishInput = {
    
    
      TopicArn: this.topicArn,
      Message: message,
    };

    await this.sns.publish(publishParams).promise();
    console.log('Message published to the topic.');
  }

  // 订阅已创建的主题
  async subscribeToTopic(endpoint: string, protocol: string): Promise<void> {
    
    
    if (!this.topicArn) {
    
    
      throw new Error('Topic not created. Call createTopic() first.');
    }

    const subscribeParams: AWS.SNS.SubscribeInput = {
    
    
      Protocol: protocol,
      TopicArn: this.topicArn,
      Endpoint: endpoint,
    };

    const result = await this.sns.subscribe(subscribeParams).promise();
    console.log(`Subscribed to the topic with subscription ARN: ${
      
      result.SubscriptionArn}`);
  }
}

其使用场景除了发布/订阅模型的通知系统;还有如下:

  1. 实时事件通知:
    场景: 当您的应用程序需要实时响应事件,例如新用户注册、订单状态变更等时,使用 SNS 可以确保消息的即时传递,而不需要轮询或长轮询。

  2. 异步任务通知:
    场景: 在分布式系统中,当异步任务完成时,可以使用 SNS发送通知。例如,后台任务处理完成后,可以发布一条通知,而前端应用程序可以订阅该通知以及时更新用户界面。

  3. 系统健康检查和报警:
    场景: 在监控系统中,当系统的健康状态发生变化时,例如服务器故障、资源超过阈值等,SNS可以用于发送报警通知给相关的团队或个人,以便他们可以及时采取行动。

  4. 移动推送通知:
    场景: 对于移动应用程序,SNS 提供了移动推送服务,可以用于向 iOS、Android 和 Kindle设备发送推送通知。这对于推送应用程序更新、提醒用户等方面非常有用。

  5. 日志和审计事件:
    场景: 当您需要记录和审计系统中的关键事件时,SNS 可以用于将日志信息发送到相关团队或存储中。这有助于及时发现和解决潜在的问题。

  6. 多通道通知:
    场景: SNS 不仅支持通过电子邮件、短信、HTTP/S等方式发送通知,还支持自定义端点。这使得可以根据不同的场景选择合适的通知通道,以确保消息能够准确地传递到目标。

SQS

import {
    
     Injectable } from '@nestjs/common';
import * as AWS from 'aws-sdk';

@Injectable()
export class SqsService {
    
    
  private readonly sqs: AWS.SQS;
  private queueUrl: string;

  constructor() {
    
    
    // 初始化 AWS SQS 实例
    this.sqs = new AWS.SQS();
    AWS.config.update({
    
     region: 'your-region' }); // 替换为您的 AWS 区域
  }

  // 创建 SQS 队列
  async createQueue(queueName: string): Promise<void> {
    
    
    const queueParams: AWS.SQS.CreateQueueRequest = {
    
    
      QueueName: queueName,
    };

    const result = await this.sqs.createQueue(queueParams).promise();
    this.queueUrl = result.QueueUrl;
    console.log(`Queue created with URL: ${
      
      this.queueUrl}`);
  }

  // 发送消息到 SQS 队列
  async sendMessage(message: string): Promise<void> {
    
    
    if (!this.queueUrl) {
    
    
      throw new Error('Queue not created. Call createQueue() first.');
    }

    const sendMessageParams: AWS.SQS.SendMessageRequest = {
    
    
      QueueUrl: this.queueUrl,
      MessageBody: message,
    };

    await this.sqs.sendMessage(sendMessageParams).promise();
    console.log('Message sent to the queue.');
  }

  // 从 SQS 队列接收消息
  async receiveMessage(): Promise<string | null> {
    
    
    if (!this.queueUrl) {
    
    
      throw new Error('Queue not created. Call createQueue() first.');
    }

    const receiveMessageParams: AWS.SQS.ReceiveMessageRequest = {
    
    
      QueueUrl: this.queueUrl,
      MaxNumberOfMessages: 1,
      VisibilityTimeout: 30, // 设置消息不可见的时间(秒)
    };

    const result = await this.sqs.receiveMessage(receiveMessageParams).promise();

    if (result.Messages && result.Messages.length > 0) {
    
    
      const message = result.Messages[0].Body;
      // 删除已接收的消息,避免其他消费者再次接收到
      await this.deleteMessage(result.Messages[0].ReceiptHandle);
      return message;
    } else {
    
    
      console.log('No messages available in the queue.');
      return null;
    }
  }

  // 删除 SQS 队列中的消息
  async deleteMessage(receiptHandle: string): Promise<void> {
    
    
    const deleteMessageParams: AWS.SQS.DeleteMessageRequest = {
    
    
      QueueUrl: this.queueUrl,
      ReceiptHandle: receiptHandle,
    };

    await this.sqs.deleteMessage(deleteMessageParams).promise();
    console.log('Message deleted from the queue.');
  }
}

上述代码中SqsService 提供了四个主要方法:

createQueue(queueName: string): Promise: 创建 SQS 队列。
sendMessage(message: string): Promise: 发送消息到已创建的队列。
receiveMessage(): Promise<string | null>: 从队列中接收消息。
deleteMessage(receiptHandle: string): Promise: 删除队列中的消息。

其使用场景能应用如下:

  1. 削峰填谷:
    场景: 当应用程序面临突发的请求激增时,可以使用 SQS缓冲这些请求,避免超负荷情况。生产者将请求发送到队列,而消费者按照其自身速度处理这些请求,实现了削峰填谷的效果。
  2. 异步任务处理:
    场景: 当应用程序需要处理一些耗时的任务,例如图像处理、数据分析等,可以将任务放入 SQS队列中,由后台异步处理,以避免阻塞主要应用程序流程。
  3. 解耦系统组件:
    场景: 在分布式系统中,不同的组件可能需要进行通信,但为了降低耦合性,可以使用 SQS作为消息队列,使得这些组件之间只需要了解消息的格式而不需要直接通信。
  4. 事件驱动架构:
    场景: SQS 可以作为事件驱动架构中的重要组成部分。当一个组件发生某个事件时,可以将相关信息发布到 SQS主题,而其他组件则可以订阅这个主题以接收事件通知。
  5. 数据流处理:
    场景: 当需要处理大量实时数据流时,SQS可以作为缓冲器,将数据发送到队列,而后台服务按照其处理能力逐步处理这些数据,以确保数据不会丢失且处理过程不会超负荷。
  6. 微服务通信:
    场景: 在微服务架构中,各个微服务可以使用 SQS 进行异步通信。例如,一个微服务可以将某个状态更改的通知发布到 SQS
    主题,而其他微服务则可以订阅这个主题以获取状态更改通知。
  7. 跨地理位置的通信:
    场景: 当系统的组件分布在不同的地理位置时,SQS可以作为它们之间进行异步通信的可靠方式,确保消息在网络不稳定的环境中仍然可靠传递。
  8. 错误处理和重试:
    场景: SQS具有内置的消息保留和重试机制,可以在处理消息时发生错误时进行重试。这使得在出现故障时能够更可靠地处理消息。

Lambda

import {
    
     Injectable } from '@nestjs/common';
import * as AWS from 'aws-sdk';

@Injectable()
export class LambdaService {
    
    
  private readonly lambda: AWS.Lambda;
  private functionArn: string;

  constructor() {
    
    
    // 初始化 AWS Lambda 实例
    this.lambda = new AWS.Lambda();
    AWS.config.update({
    
     region: 'your-region' }); // 替换为您的 AWS 区域
  }

  // 创建 Lambda 函数
  async createLambdaFunction(
    functionName: string,
    handler: string,
    roleArn: string,
    runtime: string,
  ): Promise<void> {
    
    
    const functionParams: AWS.Lambda.CreateFunctionRequest = {
    
    
      FunctionName: functionName,
      Handler: handler,
      Role: roleArn,
      Runtime: runtime,
      // 可以根据您的需求添加其他参数
    };

    const result = await this.lambda.createFunction(functionParams).promise();
    this.functionArn = result.FunctionArn;
    console.log(`Lambda function created with ARN: ${
      
      this.functionArn}`);
  }

  // 调用 Lambda 函数
  async invokeLambdaFunction(payload: any): Promise<any> {
    
    
    if (!this.functionArn) {
    
    
      throw new Error('Lambda function not created. Call createLambdaFunction() first.');
    }

    const invokeParams: AWS.Lambda.InvocationRequest = {
    
    
      FunctionName: this.functionArn,
      Payload: JSON.stringify(payload),
    };

    const result = await this.lambda.invoke(invokeParams).promise();
    const responsePayload = JSON.parse(result.Payload as string);
    console.log('Lambda function invoked with response:', responsePayload);

    return responsePayload;
  }

  // 删除 Lambda 函数
  async deleteLambdaFunction(): Promise<void> {
    
    
    if (!this.functionArn) {
    
    
      throw new Error('Lambda function not created. Call createLambdaFunction() first.');
    }

    const deleteParams: AWS.Lambda.DeleteFunctionRequest = {
    
    
      FunctionName: this.functionArn,
    };

    await this.lambda.deleteFunction(deleteParams).promise();
    console.log('Lambda function deleted.');
  }
}

Lambda能用于以下场景:

  1. 事件驱动的计算: 场景: 在 Lambda 中,您可以配置不同的事件源,如 Amazon S3、Amazon 、DynamoDB、Amazon Kinesis 等。Lambda 函数会在事件发生时被触发,例如在对象上传到 S3 桶时执行某些操作。
  2. API 后端服务: 场景: 使用 Lambda 作为后端服务来处理 API 请求。通过结合 API Gateway,您可以创建一个可扩展的、无服务器的 API 后端,Lambda 会根据请求处理并返回响应。
  3. 数据处理和转换: 场景: Lambda 可以用于处理、转换和清理大量的数据。例如,对于在 S3 存储的大型数据集,Lambda可以对每个对象执行特定的数据处理任务。
  4. 实时文件处理: 场景: 当有新的文件上传到存储服务时,Lambda可以自动触发,并执行相关的文件处理任务。这对于实现实时文件处理非常有用。
  5. 后台任务和异步处理: 场景: Lambda 可以用于执行异步任务,例如发送电子邮件通知、生成报告等。通过将任务放入消息队列(如SQS)中,Lambda 可以在任务可用时进行处理。
  6. 自动化和脚本: 场景: Lambda 可以用于自动化任务,例如定时运行脚本、执行清理任务等。通过使用 CloudWatch Events或者直接配置定时触发器,Lambda 函数可以按计划执行。
  7. 实时数据流处理: 场景: 对于实时数据流,Lambda 可以与 Kinesis等服务一起使用,以进行实时的数据处理和分析。这对于构建实时分析和仪表板非常有用。
  8. 身份验证和授权: 场景: Lambda 可以用于自定义身份验证和授权逻辑。例如,您可以使用 Lambda 来验证 API请求的令牌或执行自定义授权检查。
  9. 图像和媒体处理: 场景: Lambda 可以用于处理图像和媒体文件,例如生成缩略图、转码视频等。与 S3事件结合使用,可以实现自动的图像和媒体处理流程。
  10. 物联网(IoT)应用: 场景: Lambda 可以与 AWS IoT 服务结合使用,处理从设备发送的消息,执行设备控制和数据处理。

AWS Lambda、Amazon SQS 和 Amazon SNS 组合在一起可以构建灵活的、高度可扩展的分布式系统。
以下演示了如何使用 Node.js(使用 AWS SDK for JavaScript)在 NestJS 中组合使用这三个服务。假定已经在 AWS 控制台上创建了相应的 Lambda 函数、SQS 队列和 SNS 主题。

import {
    
     Injectable } from '@nestjs/common';
import * as AWS from 'aws-sdk';

@Injectable()
export class LambdaSqsSnsService {
    
    
  private readonly lambda: AWS.Lambda;
  private readonly sqs: AWS.SQS;
  private readonly sns: AWS.SNS;

  private lambdaFunctionName: string;
  private sqsQueueUrl: string;
  private snsTopicArn: string;

  constructor() {
    
    
    // 初始化 AWS Lambda、SQS 和 SNS 实例
    this.lambda = new AWS.Lambda();
    this.sqs = new AWS.SQS();
    this.sns = new AWS.SNS();

    AWS.config.update({
    
     region: 'your-region' }); // 替换为您的 AWS 区域

    // 替换为您的 Lambda 函数名称
    this.lambdaFunctionName = 'your-lambda-function-name';
    // 替换为您的 SQS 队列 URL
    this.sqsQueueUrl = 'your-sqs-queue-url';
    // 替换为您的 SNS 主题 ARN
    this.snsTopicArn = 'your-sns-topic-arn';
  }

  // 触发 Lambda 函数
  async invokeLambdaFunction(payload: any): Promise<any> {
    
    
    const invokeParams: AWS.Lambda.InvocationRequest = {
    
    
      FunctionName: this.lambdaFunctionName,
      Payload: JSON.stringify(payload),
    };

    const result = await this.lambda.invoke(invokeParams).promise();
    const responsePayload = JSON.parse(result.Payload as string);
    console.log('Lambda function invoked with response:', responsePayload);

    return responsePayload;
  }

  // 发送消息到 SQS 队列
  async sendMessageToQueue(message: string): Promise<void> {
    
    
    const sendMessageParams: AWS.SQS.SendMessageRequest = {
    
    
      QueueUrl: this.sqsQueueUrl,
      MessageBody: message,
    };

    await this.sqs.sendMessage(sendMessageParams).promise();
    console.log('Message sent to the SQS queue.');
  }

  // 订阅 SNS 主题
  async subscribeToTopic(endpoint: string): Promise<void> {
    
    
    const subscribeParams: AWS.SNS.SubscribeInput = {
    
    
      Protocol: 'sqs',
      TopicArn: this.snsTopicArn,
      Endpoint: this.sqsQueueUrl,
    };

    const result = await this.sns.subscribe(subscribeParams).promise();
    console.log(`Subscribed SQS queue to SNS topic with subscription ARN: ${
      
      result.SubscriptionArn}`);
  }

  // 发布消息到 SNS 主题
  async publishMessageToTopic(message: string): Promise<void> {
    
    
    const publishParams: AWS.SNS.PublishInput = {
    
    
      TopicArn: this.snsTopicArn,
      Message: message,
    };

    await this.sns.publish(publishParams).promise();
    console.log('Message published to the SNS topic.');
  }
}

invokeLambdaFunction(payload: any): Promise: 调用 Lambda 函数。
sendMessageToQueue(message: string): Promise: 发送消息到 SQS 队列。
subscribeToTopic(endpoint: string): Promise: 订阅 SNS 主题。
publishMessageToTopic(message: string): Promise: 发布消息到 SNS 主题

以下是一个实际的应用场景,可以使用 AWS Lambda、Amazon SQS 和 Amazon SNS 的组合来构建一个分布式、可伸缩、异步处理的系统。

场景描述:
假设当前正在构建一个在线电商平台,用户可以上传商品图片,而系统需要进行图像处理,包括生成缩略图和执行图像识别。在这个场景中,我们将使用 Lambda 函数处理图像,SQS 队列存储待处理的图像任务,而 SNS 主题用于发布图像处理完成的通知。

创建 NestJS 服务

// image-processing.service.ts
import {
    
     Injectable } from '@nestjs/common';
import * as AWS from 'aws-sdk';
import * as sharp from 'sharp';

@Injectable()
export class ImageProcessingService {
    
    
  private s3 = new AWS.S3();
  private sqs = new AWS.SQS();
  private sns = new AWS.SNS();

  async processImage(bucket: string, key: string): Promise<void> {
    
    
    try {
    
    
      // 从 S3 下载图像
      const image = await this.s3.getObject({
    
     Bucket: bucket, Key: key }).promise();

      // 图像处理 - 生成缩略图
      const thumbnailBuffer = await sharp(image.Body).resize(100, 100).toBuffer();

      // 将缩略图上传到 S3
      const thumbnailKey = `thumbnails/${
      
      key}`;
      await this.s3.putObject({
    
     Bucket: bucket, Key: thumbnailKey, Body: thumbnailBuffer }).promise();

      // 发送图像处理完成的通知到 SNS 主题
      await this.sns.publish({
    
    
        TopicArn: 'your-sns-topic-arn', // 替换成实际的 SNS 主题 ARN
        Message: `Image processed: ${
      
      key}`,
      }).promise();

      // 可选:将原图和缩略图信息发送到 SQS 队列进行进一步处理
      await this.sqs.sendMessage({
    
    
        QueueUrl: 'your-sqs-queue-url', // 替换成实际的 SQS 队列 URL
        MessageBody: JSON.stringify({
    
     originalKey: key, thumbnailKey }),
      }).promise();
    } catch (error) {
    
    
      console.error('处理图像出错:', error);
      throw new Error('处理图像出错');
    }
  }
}

创建 NestJS 控制器:

// image-processing.controller.ts
import {
    
     Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import {
    
     FileInterceptor } from '@nestjs/platform-express';
import {
    
     ImageProcessingService } from './image-processing.service';

@Controller('images')
export class ImageProcessingController {
    
    
  constructor(private readonly imageProcessingService: ImageProcessingService) {
    
    }

  @Post('upload')
  @UseInterceptors(FileInterceptor('image'))
  async uploadImage(@UploadedFile() file): Promise<void> {
    
    
    // 假设 'image' 是表单数据中上传图像的字段名
    const bucket = 'your-s3-bucket-name'; // 替换成实际的 S3 存储桶名
    const key = file.originalname; // 假设使用原始文件名作为键

    // 上传图像到 S3
    await this.imageProcessingService.processImage(bucket, key);

    // 返回成功响应
    return;
  }
}


NestJS 模块配置

// image-processing.module.ts
import {
    
     Module } from '@nestjs/common';
import {
    
     ImageProcessingController } from './image-processing.controller';
import {
    
     ImageProcessingService } from './image-processing.service';

@Module({
    
    
  controllers: [ImageProcessingController],
  providers: [ImageProcessingService],
})
export class ImageProcessingModule {
    
    }


应用根模块配置:

// app.module.ts
import {
    
     Module } from '@nestjs/common';
import {
    
     ImageProcessingModule } from './image-processing/image-processing.module';

@Module({
    
    
  imports: [ImageProcessingModule],
})
export class AppModule {
    
    }


通过 FileInterceptor 拦截器,NestJS 控制器接收上传的图像文件。然后,图像处理服务 (ImageProcessingService) 负责处理图像,生成缩略图,将其上传到 S3 存储桶,并发送通知到 SNS 主题。如果需要,还可以将原图和缩略图的信息发送到 SQS 队列进行后续处理。

另外一个例子是:

  1. 用户下单:用户在网站上下单购买商品。
  2. 订单处理:通过 AWS API Gateway,前端应用将订单数据发送到 AWS Lambda 函数进行订单处理。
  3. Lambda 函数执行:Lambda 函数执行订单处理逻辑,例如验证订单、计算总价、生成订单号等。
  4. 发送订单到 SQS 队列:订单处理完成后,Lambda 函数将订单数据发送到 SQS 队列。SQS 队列充当一个消息缓冲区,存储待处理的订单。
  5. 订单处理微服务:后端微服务(可以是单个服务或多个微服务)作为 SQS 队列的消费者,定期轮询队列,获取待处理的订单消息,并进行进一步的订单处理,如更新数据库、生成发货单等。
  6. 订单通知:当订单处理完成时,微服务通过 Amazon SNS 发布订单通知到相关主题。例如,有一个主题用于发送订单确认邮件,另一个主题用于将订单状态推送到用户的移动设备。
  7. 用户通知:订单确认邮件通过 Amazon SNS 发送给用户的邮箱。用户还可以通过移动设备接收到订单状态的推送通知。

优势和用例:

  • 弹性和可伸缩性:使用 Lambda 处理订单可以根据请求量自动扩展,无需手动管理服务器资源。SQS
    队列可以处理突发性订单,确保订单不会丢失。
  • 异步处理: 使用 SQS 队列将订单数据异步传递给后端微服务,实现异步处理。这有助于提高系统的可响应性和吞吐量。 解耦和
  • 可维护性:将订单数据通过 SQS 队列传递可以解耦前端 Lambda 函数和后端微服务,使它们能够独立演化和扩展。
  • 通知和推送:使用 SNS 主题可以方便地实现通知和推送功能,将订单状态通知用户。

猜你喜欢

转载自blog.csdn.net/weixin_45047825/article/details/134467756
SNS