Lambda 无服务器计算

AWS Lambda 是事件驱动的无服务器计算服务,让你无需管理服务器即可运行代码。

核心概念

什么是无服务器(Serverless)

无服务器不是没有服务器,而是指:

  • 开发者无需管理服务器
  • 按实际执行时间付费
  • 自动扩展,无需配置
  • 高可用性内置

Lambda 架构

触发器(Trigger)
    │
    ├─ API Gateway      HTTP 请求触发
    ├─ S3 Event         文件上传触发
    ├─ DynamoDB Stream  数据变更触发
    ├─ CloudWatch Event 定时任务触发
    ├─ SNS/SQS          消息队列触发
    └─ EventBridge      事件总线触发
    │
    ▼
Lambda 函数
    │
    ├─ 执行环境(Runtime)
    │    ├─ Python 3.x
    │    ├─ Node.js 18.x
    │    ├─ Java 17
    │    ├─ Go 1.x
    │    └─ Custom Runtime
    │
    ├─ 执行上下文
    │    ├─ 内存:128MB - 10GB
    │    ├─ 超时:最长 15 分钟
    │    ├─ 临时存储:/tmp(最大 10GB)
    │    └─ 环境变量
    │
    └─ IAM 角色权限
    │
    ▼
输出/集成
    ├─ 返回结果
    ├─ 调用其他服务
    ├─ 写入数据库
    └─ 发送通知

Lambda 的工作原理

冷启动与热启动

冷启动(Cold Start):

  1. 下载代码包
  2. 启动执行环境
  3. 初始化运行时
  4. 执行初始化代码
  5. 执行函数代码

耗时:Java 约 1-5 秒,Python/Node.js 约 100-500ms

热启动(Warm Start):

  • 复用已有的执行环境
  • 直接执行函数代码
  • 耗时:通常 < 10ms

优化策略:

  • 使用 Provisioned Concurrency(预配置并发)
  • 减小部署包大小
  • 最小化初始化代码
  • 选择启动快的运行时(Python、Node.js)

并发模型

请求流量
    │
    ├─ 1000 并发请求
    │
    ▼
Lambda 服务
    │
    ├─ 创建 1000 个执行环境
    ├─ 每个处理 1 个请求
    ├─ 并发上限:
    │    ├─ 账户默认:1000
    │    ├─ 可申请提升至 10,000+
    │    └─ 预留并发(Reserved Concurrency)
    │
    └─ 空闲后保留 5-15 分钟

并发类型:

  • Unreserved(未预留):与其他函数共享账户并发
  • Reserved(预留):专属并发,不与其他函数共享
  • Provisioned(预配置):预先初始化,消除冷启动

使用场景

1. Web API 后端

客户端 → API Gateway → Lambda → DynamoDB
                          ↓
                      CloudWatch Logs

优势:

  • 自动扩展应对流量峰值
  • 按请求付费,低成本
  • 无需管理服务器

示例架构:

# Lambda Handler
def lambda_handler(event, context):
    # 解析 API Gateway 请求
    http_method = event['httpMethod']
    path = event['path']
    body = json.loads(event['body']) if event['body'] else {}
    
    # 业务逻辑
    if http_method == 'GET':
        result = get_data(path)
    elif http_method == 'POST':
        result = create_data(body)
    
    # 返回响应
    return {
        'statusCode': 200,
        'headers': {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*'
        },
        'body': json.dumps(result)
    }

2. 数据处理流水线

S3 上传 → Lambda(数据转换) → S3 存储
    ↓
Lambda(生成缩略图)
    ↓
S3 存储缩略图

场景:

  • 图片/视频处理
  • 日志分析
  • ETL 任务
  • 实时数据转换

3. 定时任务(Cron Jobs)

CloudWatch Events (Cron) → Lambda → 执行任务
                                ↓
                            发送通知/报告

示例:

  • 每日数据备份
  • 定期清理过期数据
  • 生成业务报表
  • 健康检查和监控

4. 事件驱动应用

DynamoDB Streams → Lambda → 同步到 Elasticsearch
SNS Topic → Lambda → 发送邮件/短信
SQS Queue → Lambda → 异步处理任务

Lambda 最佳实践

1. 函数设计原则

单一职责:

  • 每个函数只做一件事
  • 易于测试和维护
  • 便于独立扩展

无状态设计:

  • 不依赖本地存储
  • 使用 S3/DynamoDB 存储状态
  • 每次调用独立执行

快速执行:

  • 控制执行时间 < 30 秒
  • 长任务拆分为多个小任务
  • 使用 Step Functions 编排复杂流程

2. 性能优化

减少冷启动:

# ❌ 不好:每次都初始化
def lambda_handler(event, context):
    import boto3
    s3 = boto3.client('s3')
    # ...

# ✅ 好:在函数外初始化(复用)
import boto3
s3 = boto3.client('s3')

def lambda_handler(event, context):
    # 使用已初始化的 s3 客户端
    # ...

合理配置内存:

  • 内存越大,CPU 性能越强
  • 增加内存可能降低总成本(执行更快)
  • 使用 Lambda Power Tuning 工具优化

连接池复用:

# 数据库连接复用
import pymysql

# 全局连接(在函数外)
connection = None

def get_connection():
    global connection
    if connection is None:
        connection = pymysql.connect(
            host='database.example.com',
            user='admin',
            password='password',
            database='mydb'
        )
    return connection

def lambda_handler(event, context):
    conn = get_connection()
    # 使用连接...

3. 错误处理

重试策略:

def lambda_handler(event, context):
    max_retries = 3
    retry_count = 0
    
    while retry_count < max_retries:
        try:
            result = process_data(event)
            return result
        except Exception as e:
            retry_count += 1
            if retry_count >= max_retries:
                # 发送到 DLQ(死信队列)
                send_to_dlq(event, str(e))
                raise
            time.sleep(2 ** retry_count)  # 指数退避

死信队列(DLQ):

  • 捕获失败的事件
  • 便于调试和重新处理
  • 使用 SQS 或 SNS

4. 安全实践

最小权限原则:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::my-bucket/uploads/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:PutItem",
        "dynamodb:GetItem"
      ],
      "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/MyTable"
    }
  ]
}

敏感数据管理:

  • 使用环境变量(加密)
  • 使用 Secrets Manager 或 Parameter Store
  • 不在代码中硬编码密钥

Lambda 定价

计费模型

请求数:

  • 前 100 万次请求/月:免费
  • 之后:$0.20 / 100 万次请求

执行时间:

  • 前 40 万 GB-秒/月:免费
  • 之后:$0.0000166667 / GB-秒

GB-秒计算:

执行时间(秒) × 内存(GB) = GB-秒

示例:
- 1000 次请求
- 每次执行 200ms (0.2秒)
- 内存 512MB (0.5GB)

总 GB-秒 = 1000 × 0.2 × 0.5 = 100 GB-秒
成本 ≈ 100 × $0.0000166667 = $0.00167

成本优化

选择合适的内存:

  • 内存越大,CPU 越强,但单价越高
  • 找到性能/成本的最佳平衡点

使用 ARM(Graviton2):

  • 比 x86 便宜 20%
  • 性能相当或更好
  • 适合计算密集型任务

预留并发(Provisioned Concurrency):

  • 消除冷启动
  • 但会增加成本(按预留时间计费)
  • 仅在需要低延迟时使用

Lambda 限制

执行限制

限制项
内存 128 MB - 10 GB
临时存储(/tmp) 512 MB - 10 GB
超时 最长 15 分钟
环境变量 4 KB
部署包大小(压缩) 50 MB
部署包大小(解压) 250 MB
并发执行数 默认 1000(可申请提升)

网络限制

  • VPC Lambda:需要 NAT Gateway 访问互联网
  • 公网 Lambda:无法访问 VPC 内资源(除非配置 VPC)
  • 出站连接:受 VPC 安全组和 NACL 限制

Lambda vs. 传统服务器

维度 Lambda EC2
成本 按执行时间付费,低流量低成本 按小时付费,一直运行
扩展 自动扩展,无需配置 需配置 Auto Scaling
维护 零维护,AWS 管理 需打补丁、更新系统
启动 毫秒级(热启动) 分钟级
长任务 最长 15 分钟 无限制
状态 无状态 可有状态
冷启动 存在冷启动延迟 无冷启动

何时使用 Lambda

✅ 适合场景:

  • 事件驱动的任务
  • 短时间执行(< 15 分钟)
  • 间歇性流量
  • 需要快速扩展
  • 不想管理服务器

❌ 不适合场景:

  • 长时间运行任务(> 15 分钟)
  • 需要持久连接(WebSocket)
  • 有状态应用
  • 对冷启动敏感且高 QPS
  • 需要专用硬件(GPU)

监控与调试

CloudWatch Logs

每个 Lambda 函数自动集成 CloudWatch Logs:

  • 查看执行日志
  • 监控错误和异常
  • 分析性能指标

X-Ray 分布式追踪

启用 X-Ray 后可以:

  • 可视化请求流程
  • 识别性能瓶颈
  • 分析服务依赖关系

关键指标

  • Invocations:调用次数
  • Duration:执行时间
  • Errors:错误次数
  • Throttles:限流次数
  • Concurrent Executions:并发执行数
  • Iterator Age:事件处理延迟(流处理)

Lambda 是构建现代无服务器应用的核心服务,掌握它是云原生开发的关键技能!