备考助手
📌 核心知识点
函数设计模式冷启动优化并发控制成本优化
Lambda 无服务器实战
📖 Lambda 基础知识
AWS Lambda 是 AWS 的无服务器计算服务,让用户无需管理服务器即可运行代码。Lambda 是 AWS 无服务器架构的核心服务,与 API Gateway、DynamoDB、AWS Batch 配合使用。
🖼️ Lambda 图解补充

看图重点:Lambda 可作为 ALB 目标,入口流量治理和函数并发要联动。

看图重点:旧架构迁移时常会从 CLB 迁到 ALB + Lambda 或容器。

看图重点:Lambda 与容器常并存,按延迟与运维复杂度选择执行载体。

看图重点:函数执行失败且访问 AWS 服务被拒时,先查角色策略链路。

看图重点:Lambda 进 VPC 后网络路径更复杂,冷启动与连通性都要关注。

看图重点:函数频繁跨区调用会放大传输费用,架构上应尽量就近部署。

看图重点:函数数量增长后要靠标签做精细成本治理。
无服务器的理念
"无服务器"意味着用户不需要管理物理机器的配置、扩展或维护。Lambda 执行用户代码的机器被抽象为"容器"。
触发器 → Lambda 函数 → 目标服务
│ │ │
事件源 执行代码 输出结果
(API GW, (Node.js, (DynamoDB,
S3, SQS) Python等) S3, SNS)
支持的运行时
| 运行时 | 版本 | 冷启动时间 | 适用场景 |
|---|---|---|---|
| Node.js | 18.x, 20.x | ~200ms | API、数据处理 |
| Python | 3.9-3.12 | ~200ms | 数据科学、自动化 |
| Java | 11, 17, 21 | ~1-3s | 企业应用 |
| Go | 1.x | ~100ms | 高性能 |
| .NET | 6, 8 | ~500ms | C# 应用 |
| Ruby | 3.2 | ~300ms | 脚本任务 |
内存与 CPU 的关系
# 重要:更多内存 = 更多 CPU 能力!
# Lambda 内存配置直接影响 CPU:
128 MB → 最小 CPU 份额
1792 MB → 1 个完整 vCPU
10240 MB → 6 个 vCPU
# 所以即使不需要更多内存,
# 增加内存配置也可以加速 CPU 密集型任务

看图重点:Reserved Concurrency 可以给关键函数保底容量,也能限制“问题函数”抢占全部并发。

看图重点:并发打满时先看 ConcurrentExecutions 与 Throttles,再决定扩容或限流。
函数设计模式
单一职责
# ✅ 推荐: 每个函数做一件事
def process_order(event, context):
order = parse_order(event)
validate_order(order)
save_order(order)
return {"status": "success"}
# ❌ 不推荐: 函数过于复杂
def do_everything(event, context):
# 处理订单、发送邮件、更新库存...
pass
容器复用和缓存
# 💡 关键优化:利用容器复用
# 在 handler 外部初始化 (只在冷启动时执行一次)
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('my-table')
# 缓存应用数据
_cached_config = None
def get_config():
global _cached_config
if _cached_config is None:
_cached_config = load_config_from_s3()
return _cached_config
def handler(event, context):
# 使用已初始化的连接和缓存
config = get_config()
response = table.get_item(Key={'id': event['id']})
return response
虽然 AWS 不提供容器复用的硬性保证,但通常如果短时间内再次调用同一函数,Lambda 会复用已有的"热"容器。
事件驱动架构
用户请求 → API Gateway → Lambda (验证)
│
▼
SQS 队列
│
▼
Lambda (处理)
│
▼
DynamoDB
扇出模式
# 主函数将任务分发给多个 worker
def main_handler(event, context):
tasks = split_tasks(event)
for task in tasks:
lambda_client.invoke(
FunctionName='worker-function',
InvocationType='Event', # 异步调用
Payload=json.dumps(task)
)
# 示例项目: aws-lambda-fanout
# https://github.com/awslabs/aws-lambda-fanout
定时任务 (类似 Cron)
# 使用 CloudWatch Events 定时触发 Lambda
# cron 表达式示例:
# 每天 UTC 时间 10:00 执行
aws events put-rule \
--name "DailyTrigger" \
--schedule-expression "cron(0 10 * * ? *)"
# 每 5 分钟执行
aws events put-rule \
--name "Every5Minutes" \
--schedule-expression "rate(5 minutes)"
冷启动优化
什么是冷启动?
冷启动流程:
下载代码 → 创建容器 → 初始化运行时 → 执行代码
(~100ms) (~200ms) (~50ms) (你的代码)
热启动流程:
执行代码 (直接使用已有容器,毫秒级)
冷启动性能在 2018-2019 年间有了显著改进,现在简单函数的冷启动通常在 200-500ms 范围内。
VPC 内 Lambda 冷启动改进
# 重大改进!
# 之前:VPC 内 Lambda 冷启动约 15 秒
# 现在:VPC 内 Lambda 冷启动 < 1 秒
# AWS 通过改进 ENI 分配机制实现了这一优化
# https://aws.amazon.com/blogs/compute/announcing-improved-vpc-networking-for-aws-lambda-functions/
优化策略
1. 使用 Provisioned Concurrency
# 最有效消除冷启动的方法(re:invent 2019 发布)
aws lambda put-provisioned-concurrency-config \
--function-name my-function \
--qualifier prod \
--provisioned-concurrent-executions 10
# 预热的容器始终就绪
# 但会持续产生费用
2. 减少部署包大小
# 使用 Lambda Layer 分离依赖
aws lambda publish-layer-version \
--layer-name my-dependencies \
--zip-file fileb://layer.zip
# 对于 Java:使用 ProGuard 优化
# 或者在运行时将依赖加载到 /tmp
3. 选择轻量级运行时
# 冷启动时间排序(从快到慢):
1. Go (~100ms)
2. Python (~200ms)
3. Node.js (~200ms)
4. .NET (~500ms)
5. Java (~1-3s)
# 对于延迟敏感的场景,优先考虑 Go 或 Python
4. 定期触发保持热容器
# 使用 CloudWatch Events 每 5 分钟触发一次
# 保持容器温暖
def handler(event, context):
# 检查是否为预热触发
if event.get('source') == 'aws.events':
return {'statusCode': 200, 'body': 'warmup'}
# 正常业务逻辑
...
并发控制
并发类型
账户并发限制: 1000 (可申请提升到数万)
│
├── 函数 A: 预留并发 100
│ └── 最多 100 个并发执行
│
├── 函数 B: 预留并发 200
│ └── 最多 200 个并发执行
│
└── 其他函数: 共享剩余 700
设置预留并发
# 预留并发确保函数始终有可用容量
aws lambda put-function-concurrency \
--function-name my-function \
--reserved-concurrent-executions 100
# 注意:预留并发会从账户总量中扣除
处理失败和重试
# 使用 Dead Letter Queue (DLQ) 处理失败的事件
# 配置 SQS 作为 DLQ
# 在 Lambda 配置中设置:
# DeadLetterConfig:
# TargetArn: arn:aws:sqs:region:account:my-dlq
# 处理限流
import time
def handler(event, context):
try:
# 业务逻辑
pass
except ClientError as e:
if e.response['Error']['Code'] == 'TooManyRequestsException':
time.sleep(1) # 退避
raise # 重新抛出让 Lambda 重试
监控和调试
CloudWatch 集成
# Lambda 自动与 CloudWatch 集成
# 提供运行时 logger
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def handler(event, context):
logger.info(f"Processing event: {event}")
# ...
X-Ray 追踪
# Lambda 原生支持 AWS X-Ray(可选启用)
# 帮助诊断调用其他 AWS 服务时的问题
# 提供详细的调用图可视化
# 特别适合排查复杂的服务调用链
成本优化
计费模型
费用 = 请求次数 × 单价 + 执行时间(GB-秒) × 单价
示例:
- 100万次请求/月
- 每次执行 200ms, 256MB 内存
费用 = 1M × $0.20/M + 1M × 0.2s × 0.25GB × $0.0000166667
= $0.20 + $0.83
= $1.03/月
使用 ARM64 (Graviton2)
# Graviton2 处理器便宜 20%,且通常更快
aws lambda create-function \
--function-name my-function \
--architectures arm64 \
...
# 确保代码和依赖兼容 ARM
Lambda Power Tuning
# 使用 AWS Lambda Power Tuning 工具
# 找到最佳内存配置
# https://github.com/alexcasalboni/aws-lambda-power-tuning
# 它会用不同内存配置测试你的函数
# 生成性能/成本曲线,帮你做最优选择
无服务器框架
AWS SAM (Serverless Application Model)
# template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
MyFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: python3.9
Events:
Api:
Type: Api
Properties:
Path: /hello
Method: GET
# 本地测试
sam local invoke MyFunction
# 部署
sam deploy --guided
Serverless Framework
# serverless.yml
service: my-service
provider:
name: aws
runtime: python3.9
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
# 部署
serverless deploy
其他选择
API Gateway 集成
基础设置
API Gateway
├── 提供 RESTful API 前端
├── 自动扩展
├── 支持 OpenAPI/Swagger
├── 内置 CloudWatch 日志
└── 与 Cognito 集成认证
认证选项
# 1. Amazon Cognito(推荐大多数场景)
# 最简单的用户认证方式
# 2. 自定义授权器
# 自己写 Lambda 判断请求是否允许
# 3. API Key
# 简单的 API 访问控制
REST vs RPC 风格
# API Gateway 很适合 REST,但 RPC 风格也很好用
# REST 风格
GET /users/123
POST /users
# RPC 风格(适合内部服务)
POST /getUser
POST /createUser
# RPC 对于深层服务可能更简单清晰
⚠️ Lambda 常见陷阱
1. 资源限制
# 重要限制(2024年):
请求/响应负载: 6 MB(同步)
部署包 (zip): 50 MB(压缩后)
代码/依赖: 250 MB(解压后)
/tmp 临时存储: 10 GB
执行超时: 最大 15 分钟
# Java 部署包特别容易超限
# 考虑使用 ProGuard 或运行时加载依赖到 /tmp
2. VPC 相关问题
# 🔸 VPC 内 Lambda 需要 NAT Gateway 访问外网
# 即使在公有子网也不会分配公有 IP!
# 🔸 ENI 数量限制
# 每个并发 Lambda 需要一个 ENI
# 初始限制约 350,可申请提升到 1000+
# 🔸 访问 AWS 服务用 VPC 端点
# 避免通过 NAT Gateway
aws ec2 create-vpc-endpoint \
--vpc-id vpc-xxx \
--service-name com.amazonaws.ap-southeast-2.s3 \
...
3. 测试挑战
# 🔸 本地测试 Lambda 是个挑战
# 官方工具:SAM Local
sam local invoke MyFunction -e event.json
sam local start-api
# 也可以用 LocalStack 模拟 AWS 服务
4. 版本和别名管理
# 🔸 AWS 官方的版本/别名管理流程很痛苦
# 建议:在 Lambda 外部管理部署流程
# 例如:每个环境一个 AWS 账户
# 只需关心最新版本
# 回滚由外部工具处理
5. S3 触发器问题
# 🔸 添加/删除 S3 触发器时可能报错:
# "Configuration is ambiguously defined..."
# 原因:两个规则的前缀/后缀重叠
# 解决:在 S3 控制台的 Events 标签手动删除旧触发器
6. DynamoDB 触发器问题
# 🔸 可能报错:
# "internal Lambda error. Please contact Lambda customer support."
# 通常是因为 DynamoDB Stream 48 小时内没有数据
# 解决:删除并重新创建触发器
7. API Gateway 限制
# 🔸 只支持 HTTPS,不支持 HTTP(这其实是好事)
# 🔸 不支持多区域部署用于高可用
# 虽然是从边缘位置提供服务,但是单区域
# 🔸 集成超时无法提高
# Lambda: 29 秒
# HTTP: 29 秒
# 🔸 请求/响应过大会被 CloudWatch 截断
# 完整日志需要在 Lambda 中实现
Lambda 替代方案
| 平台 | 服务名 |
|---|---|
| Google Cloud | Cloud Functions |
| Azure | Azure Functions |
| IBM | OpenWhisk |
| Kubernetes | OpenFaaS, Knative |
📚 本章小结
- Lambda 是无服务器架构的核心,与 API Gateway、DynamoDB 配合使用
- 内存配置影响 CPU,增加内存可以加速计算
- 利用容器复用和初始化代码优化减少冷启动影响
- VPC 内 Lambda 冷启动已大幅改进(< 1秒)
- Provisioned Concurrency 可以完全消除冷启动
- 使用 DLQ 处理失败事件
- X-Ray 帮助诊断复杂调用链
- ARM64 (Graviton2) 便宜 20% 且通常更快
- 注意资源限制:6MB 负载、50MB 部署包、10GB /tmp
- VPC 内 Lambda 需要 NAT Gateway 或 VPC 端点访问外部服务