JavaScript内核与高级编程之:`JavaScript` 的 `Serverless` 架构:`AWS Lambda` 和 `Google Cloud Functions` 的 `JS` 运行时。

各位观众老爷,大家好!今天咱们聊点儿时髦的,说说 JavaScript 在 Serverless 架构里的那些事儿。特别是 AWS Lambda 和 Google Cloud Functions,这两个大佬手里的 JS 运行时,到底是怎么玩的。

开场白:Serverless,这货到底是什么?

Serverless,直译过来就是“无服务器”。但注意,这可不是真的不用服务器了! 而是说,你不用再操心服务器的配置、维护、扩展这些破事儿了。这些都交给云服务商去搞定,你只管写代码,然后让它跑起来就行。

想象一下:你写了一个简单的函数,比如一个计算器,你不用买服务器、装操作系统、配置 Web 服务器…直接把代码丢给 AWS Lambda 或者 Google Cloud Functions,它就能跑起来,而且自动伸缩,按需付费。是不是很爽?

JavaScript + Serverless = 珠联璧合?

为啥要用 JavaScript 搞 Serverless?原因很简单:

  • 前端开发者的福音: 大部分前端开发者都熟悉 JavaScript,用它来写后端逻辑,学习成本低,上手快。
  • Node.js 的流行: Node.js 让 JavaScript 也能在服务器端运行,生态系统庞大,各种库和框架应有尽有。
  • 事件驱动: Serverless 架构本身就是事件驱动的,而 JavaScript 的异步特性非常适合处理各种事件。

AWS Lambda 的 JavaScript 运行时

AWS Lambda 支持多种语言的运行时,JavaScript(Node.js)是其中之一。

1. Lambda 函数的结构

一个 Lambda 函数,本质上就是一个 JavaScript 函数,它接收两个参数:

  • event: 触发函数的事件数据。比如,如果是 HTTP 请求,event 里就包含了请求的 headers、body、query parameters 等信息。
  • context: 提供了关于函数执行、环境和调用信息的对象。比如,你可以用 context.log() 来记录日志,或者用 context.getRemainingTimeInMillis() 来查看剩余的执行时间。

下面是一个简单的 Lambda 函数的例子:

exports.handler = async (event, context) => {
  console.log('Received event:', JSON.stringify(event, null, 2));

  const response = {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Hello from Lambda!',
      input: event,
    }),
  };
  return response;
};

这个函数接收一个事件,然后返回一个包含 "Hello from Lambda!" 消息的 JSON 响应。

2. 如何部署 Lambda 函数?

部署 Lambda 函数,通常有几种方式:

  • AWS 控制台: 最简单的方式,可以直接在 AWS 控制台里上传你的代码(zip 文件),或者在线编辑代码。
  • AWS CLI: 通过命令行工具,可以更方便地自动化部署流程。
  • AWS CloudFormation/Serverless Framework/Terraform: 这些基础设施即代码(IaC)工具,可以让你用配置文件来定义和管理你的 Lambda 函数和其他 AWS 资源。

这里我们简单介绍一下用 AWS CLI 部署 Lambda 函数的步骤:

  1. 打包代码: 把你的 JavaScript 代码和 node_modules 目录打包成一个 zip 文件。

    zip -r my-lambda-function.zip .
  2. 创建 Lambda 函数: 使用 aws lambda create-function 命令。

    aws lambda create-function 
        --function-name my-lambda-function 
        --runtime nodejs18.x 
        --role arn:aws:iam::YOUR_ACCOUNT_ID:role/lambda_basic_execution 
        --handler index.handler 
        --zip-file fileb://my-lambda-function.zip
    • --function-name: Lambda 函数的名字。
    • --runtime: 使用的 Node.js 运行时版本。
    • --role: Lambda 函数的 IAM 角色,用于授权函数访问其他 AWS 资源。
    • --handler: 入口函数,格式为 文件名.函数名
    • --zip-file: 包含代码的 zip 文件。
  3. 更新 Lambda 函数代码: 如果你需要更新代码,可以使用 aws lambda update-function-code 命令。

    aws lambda update-function-code 
        --function-name my-lambda-function 
        --zip-file fileb://my-lambda-function.zip

3. Lambda 函数的触发器

Lambda 函数需要被触发才能执行。AWS 提供了多种触发器:

  • API Gateway: 将 Lambda 函数暴露为 HTTP API。
  • S3: 当 S3 桶里的对象发生变化时(比如上传、删除),触发 Lambda 函数。
  • DynamoDB: 当 DynamoDB 表里的数据发生变化时,触发 Lambda 函数。
  • CloudWatch Events: 按照预定的时间间隔触发 Lambda 函数 (Cron job)。
  • SQS: 当 SQS 队列里有消息时,触发 Lambda 函数。
  • SNS: 当 SNS 主题收到消息时,触发 Lambda 函数。

4. 实际案例:一个简单的 API Gateway + Lambda 函数

假设我们要创建一个简单的 API,当用户访问 /hello 路径时,返回 "Hello from Lambda!"。

  1. Lambda 函数代码:

    exports.handler = async (event, context) => {
      const response = {
        statusCode: 200,
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({
          message: "Hello from Lambda!"
        })
      };
      return response;
    };
  2. API Gateway 配置:

    • 在 API Gateway 里创建一个新的 API。
    • 创建一个新的 Resource,路径设置为 /hello
    • 创建一个新的 Method,类型设置为 GET
    • 将这个 Method 与你的 Lambda 函数关联起来。
    • 配置 Integration Request,选择 Lambda Function,并选择你的 Lambda 函数。
    • 配置 Integration Response,将 Lambda 函数的输出映射到 HTTP 响应。
    • 部署 API。
  3. 测试:

    部署完成后,你可以通过 API Gateway 提供的 URL 访问 /hello 路径,应该能看到 "Hello from Lambda!" 的 JSON 响应。

Google Cloud Functions 的 JavaScript 运行时

Google Cloud Functions 也支持 JavaScript(Node.js)运行时,与 AWS Lambda 类似,但也有一些区别。

1. Cloud Functions 的结构

一个 Cloud Function 也是一个 JavaScript 函数,它接收两个参数:

  • req: HTTP 请求对象。 包含了请求的 headers、body、query parameters 等信息。如果是其他类型的触发器,req 会包含不同的数据。
  • res: HTTP 响应对象。 可以用它来发送响应给客户端。

下面是一个简单的 Cloud Function 的例子:

exports.helloWorld = (req, res) => {
  console.log('Received request:', req.body);

  res.status(200).json({
    message: 'Hello from Cloud Functions!',
    input: req.body,
  });
};

这个函数接收一个 HTTP 请求,然后返回一个包含 "Hello from Cloud Functions!" 消息的 JSON 响应。

2. 如何部署 Cloud Functions?

部署 Cloud Functions,可以使用 Google Cloud CLI (gcloud)。

  1. 编写代码: 编写你的 JavaScript 代码,并创建一个 package.json 文件,指定依赖项。

  2. 部署函数: 使用 gcloud functions deploy 命令。

    gcloud functions deploy helloWorld 
        --runtime nodejs18 
        --trigger-http 
        --allow-unauthenticated
    • helloWorld: Cloud Function 的名字。
    • --runtime: 使用的 Node.js 运行时版本。
    • --trigger-http: 指定触发器类型为 HTTP。
    • --allow-unauthenticated: 允许未经身份验证的访问。

3. Cloud Functions 的触发器

Google Cloud Functions 提供了多种触发器:

  • HTTP: 将 Cloud Function 暴露为 HTTP API。
  • Cloud Storage: 当 Cloud Storage 桶里的对象发生变化时,触发 Cloud Function。
  • Cloud Pub/Sub: 当 Cloud Pub/Sub 主题收到消息时,触发 Cloud Function。
  • Cloud Firestore: 当 Cloud Firestore 数据库里的数据发生变化时,触发 Cloud Function。
  • Cloud Scheduler: 按照预定的时间间隔触发 Cloud Function (Cron job)。

4. 实际案例:一个简单的 HTTP Cloud Function

假设我们要创建一个简单的 HTTP API,当用户访问 /hello 路径时,返回 "Hello from Cloud Functions!"。

  1. Cloud Function 代码:

    exports.helloWorld = (req, res) => {
      res.status(200).json({
        message: "Hello from Cloud Functions!"
      });
    };
  2. 部署:

    gcloud functions deploy helloWorld 
        --runtime nodejs18 
        --trigger-http 
        --allow-unauthenticated
  3. 测试:

    部署完成后,你可以通过 Google Cloud Platform 提供的 URL 访问 /hello 路径,应该能看到 "Hello from Cloud Functions!" 的 JSON 响应。

AWS Lambda vs. Google Cloud Functions: 简单对比

特性 AWS Lambda Google Cloud Functions
运行时支持 Node.js, Python, Java, Go, Ruby, .NET, 自定义运行时 Node.js, Python, Go, Java, .NET, Ruby, PHP
触发器 API Gateway, S3, DynamoDB, CloudWatch Events, SQS, SNS 等 HTTP, Cloud Storage, Cloud Pub/Sub, Cloud Firestore, Cloud Scheduler 等
部署方式 AWS 控制台, AWS CLI, CloudFormation, Serverless Framework, Terraform Google Cloud CLI
身份验证 IAM Roles, API Gateway 身份验证 IAM, Identity Platform, API Keys
监控与日志 CloudWatch Cloud Logging
本地开发与测试 SAM CLI, Serverless Framework Functions Framework
价格 基于函数执行时间和内存使用量 基于函数执行时间和内存使用量
冷启动时间 通常情况下,Node.js 相对较快。 通常情况下,Node.js 相对较快。
最大执行时间 15 分钟 9 分钟

进阶话题:最佳实践和注意事项

  • 代码组织: 使用模块化的方式组织你的代码,方便维护和测试。
  • 依赖管理: 使用 package.json 管理你的依赖项,确保环境一致性。
  • 错误处理: 完善的错误处理机制,避免程序崩溃。
  • 日志记录: 使用 console.log()context.log() 记录关键信息,方便调试。
  • 安全性: 注意权限控制,避免未授权访问。
  • 性能优化: 避免长时间运行的任务,优化代码性能,减少冷启动时间。
  • 环境配置: 使用环境变量来配置你的函数,避免硬编码敏感信息。

真实案例演示:图片处理服务

假设我们要创建一个图片处理服务,当用户上传图片到 S3 桶时,Lambda 函数会自动生成缩略图。

  1. Lambda 函数代码:

    const AWS = require('aws-sdk');
    const sharp = require('sharp');
    
    const s3 = new AWS.S3();
    
    exports.handler = async (event) => {
      const bucket = event.Records[0].s3.bucket.name;
      const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/+/g, ' '));
      const params = {
        Bucket: bucket,
        Key: key,
      };
    
      try {
        const image = await s3.getObject(params).promise();
        const buffer = image.Body;
    
        const resizedImage = await sharp(buffer)
          .resize(200, 200)
          .toBuffer();
    
        const newKey = `thumbnails/${key}`;
        const uploadParams = {
          Bucket: bucket,
          Key: newKey,
          Body: resizedImage,
          ContentType: 'image/jpeg', // 根据实际情况修改
        };
    
        await s3.putObject(uploadParams).promise();
    
        console.log('Thumbnail created successfully:', newKey);
        return {
          statusCode: 200,
          body: JSON.stringify({ message: 'Thumbnail created successfully!' }),
        };
      } catch (error) {
        console.error('Error creating thumbnail:', error);
        return {
          statusCode: 500,
          body: JSON.stringify({ message: 'Error creating thumbnail!', error: error.message }),
        };
      }
    };
  2. 配置 S3 触发器:

    • 在 S3 桶里配置一个事件通知,当对象创建时,触发 Lambda 函数。
  3. 测试:

    • 上传一张图片到 S3 桶,Lambda 函数会自动生成一个缩略图,并保存在 thumbnails 目录下。

总结:Serverless 的未来

Serverless 架构正在变得越来越流行,它简化了应用开发、部署和运维流程,降低了成本,提高了效率。 JavaScript 作为一种流行的编程语言,在 Serverless 领域有着广泛的应用前景。

希望今天的分享能帮助大家更好地理解 JavaScript 在 Serverless 架构里的应用。 谢谢大家!

(下课! 欢迎大家提问。)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注