跳转至

AWS Lambda 无服务器 — 按函数调用次数付费,无需管理服务器


一句话说明

AWS Lambda 让你只写函数代码,AWS 自动管理服务器、扩容、负载均衡,函数被触发时才运行,闲置时不收费,适合处理 S3 上传事件、定时任务、API 请求等场景。


安装与配置

# 安装 AWS SAM CLI(Lambda 本地开发工具)
pip install aws-sam-cli
sam --version

# 安装 AWS CLI(如未安装)
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip && sudo ./aws/install

# 初始化 SAM 项目
sam init --runtime python3.12 --name my-lambda-app  # Python 3.12 运行时

# 项目目录结构
# my-lambda-app/
# ├── template.yaml        # SAM 模板(描述资源)
# ├── hello_world/
# │   ├── app.py           # Lambda 函数代码
# │   └── requirements.txt # Python 依赖
# └── tests/               # 测试目录
# template.yaml — SAM 模板(定义 Lambda 和触发器)
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31   # 使用 SAM 简化语法

Resources:
  ProcessFastqFunction:                  # 资源逻辑名
    Type: AWS::Serverless::Function     # Lambda 函数类型
    Properties:
      FunctionName: process-fastq        # 函数名称
      CodeUri: process_fastq/            # 代码目录
      Handler: app.lambda_handler        # 入口:文件名.函数名
      Runtime: python3.12                # 运行时
      Timeout: 900                       # 最大运行时间(秒),Lambda 最长15分钟
      MemorySize: 1024                   # 内存(MB),越大越贵但也越快
      Environment:
        Variables:
          RESULT_BUCKET: my-results-bucket  # 环境变量
      Events:
        S3Upload:                        # 触发器:S3 上传事件
          Type: S3
          Properties:
            Bucket: !Ref RawDataBucket
            Events: s3:ObjectCreated:*   # 任何文件创建都触发
            Filter:
              S3Key:
                Rules:
                  - Name: suffix
                    Value: .fastq        # 只响应 .fastq 文件

  RawDataBucket:
    Type: AWS::S3::Bucket               # 创建 S3 桶

核心用法

# process_fastq/app.py — Lambda 函数代码
import json
import boto3                            # AWS SDK
import os

# 在函数外初始化客户端(Lambda 容器复用,可提高性能)
s3 = boto3.client('s3')
result_bucket = os.environ['RESULT_BUCKET']  # 从环境变量读取桶名

def lambda_handler(event, context):
    """
    Lambda 入口函数
    event: 触发事件的数据(JSON 格式)
    context: 运行时信息(剩余时间、内存等)
    """
    print(f"接收到事件: {json.dumps(event)}")  # 打印日志(自动发送到 CloudWatch)

    # ── 从 S3 事件中提取文件信息 ──
    for record in event['Records']:             # 可能一次触发多个文件
        bucket = record['s3']['bucket']['name'] # 来源桶名
        key = record['s3']['object']['key']     # 文件路径(URL 编码)
        key = key.replace('+', ' ')             # 解码空格

        print(f"处理文件: s3://{bucket}/{key}")

        # ── 下载文件到 /tmp(Lambda 临时空间,最大 10GB)──
        local_path = f'/tmp/{os.path.basename(key)}'  # 本地临时路径
        s3.download_file(bucket, key, local_path)

        # ── 处理文件(示例:统计 FASTQ 读段数)──
        read_count = count_reads(local_path)
        print(f"读段总数: {read_count}")

        # ── 上传结果 ──
        result_key = f'results/{os.path.basename(key)}.stats.txt'
        result_content = f"File: {key}\nTotal reads: {read_count}\n"
        s3.put_object(
            Bucket=result_bucket,
            Key=result_key,
            Body=result_content.encode('utf-8'),
        )

    return {
        'statusCode': 200,
        'body': json.dumps({'message': '处理完成', 'files': len(event['Records'])}),
    }

def count_reads(fastq_path: str) -> int:
    """统计 FASTQ 文件中的读段数"""
    count = 0
    with open(fastq_path, 'r') as f:
        for line in f:
            if line.startswith('@'):    # FASTQ 每4行一个读段,@ 开头是序列头
                count += 1
    return count

实战案例

# ── 本地调试(无需部署到云端)──
sam local invoke ProcessFastqFunction \
  --event events/s3-event.json        # 模拟 S3 触发事件

# events/s3-event.json(模拟事件)
cat > events/s3-event.json << 'EOF'
{
  "Records": [{
    "s3": {
      "bucket": { "name": "my-raw-bucket" },
      "object": { "key": "sample.fastq", "size": 1024 }
    }
  }]
}
EOF

# ── 启动本地 API 端点 ──
sam local start-api                  # 在本地模拟 API Gateway

# ── 部署到 AWS ──
sam build                            # 构建函数包
sam deploy --guided                  # 引导式部署(第一次)
sam deploy                           # 后续部署(用上次配置)

# ── 查看日志 ──
sam logs -n ProcessFastqFunction --stack-name my-lambda-app --tail  # 实时日志

# ── 直接调用已部署的函数 ──
aws lambda invoke \
  --function-name process-fastq \
  --payload '{"test": true}' \       # 输入 JSON
  /tmp/output.json                   # 输出保存到本地

cat /tmp/output.json                 # 查看返回结果

常见报错与解决

报错原因解决方法
Task timed out after 3.00 seconds默认超时3秒太短在 template.yaml 中增加 Timeout
Runtime.ImportModuleError依赖未打包在 requirements.txt 加依赖,重新 sam build
No space left on device/tmp 空间(10GB)不足处理完立即删除临时文件
冷启动慢首次调用需初始化容器ProvisionedConcurrency,或换 Go/Rust 减少启动时间
AccessDeniedIAM 角色没有 S3 权限在 template.yaml 的 Policies 中添加 S3 权限

速查表

# SAM 命令
sam init            # 初始化项目
sam build           # 打包依赖
sam local invoke    # 本地调用
sam local start-api # 本地 API 模拟
sam deploy          # 部署到 AWS
sam logs            # 查看日志
sam delete          # 删除部署

# Lambda 限制(2025年)
最大运行时间: 15 分钟(900秒)
最大内存: 10 GB
/tmp 空间: 10 GB
部署包大小: 50 MB(压缩)/ 250 MB(解压)
请求并发: 1000(默认,可申请提高)

# 费用(按需计费)
 100 万次调用/月免费
超出部分: $0.20/百万次
计算费用: $0.00001667/GB-秒

# 官方文档:https://docs.aws.amazon.com/lambda/
# SAM 文档:https://docs.aws.amazon.com/serverless-application-model/