AWS Lambda 让你无需配置或管理服务器即可运行代码。你只需为消耗的计算时间付费,Lambda 会自动扩展。本指南涵盖 Lambda 基础、Node.js 和 Python 处理程序模式、API Gateway 集成、事件源、层、DynamoDB 操作、Step Functions、性能调优、测试和监控。
关键要点
- Lambda 按请求和每 GB 秒计算收费。免费层每月包含 100 万请求和 400,000 GB 秒。
- 冷启动范围从 100ms(Node.js/Python)到 1-2s(Java/.NET)。使用预置并发消除关键路径的冷启动。
- 在处理程序外初始化 SDK 客户端和数据库连接,以在热调用间重用。
- API Gateway + Lambda 是构建无服务器 REST API 最常见的模式。
- Lambda 层让你在多个函数间共享代码和依赖,无需在每次部署中捆绑。
- 使用 AWS SAM 或 CDK 进行基础设施即代码。SAM 用无服务器特定快捷方式扩展 CloudFormation。
Lambda 基础
Lambda 在 AWS 管理的短生命周期容器中运行代码。请求到达时,Lambda 重用温暖容器或创建新容器(冷启动)。
执行模型
每个 Lambda 函数有初始化阶段(冷启动)和调用阶段。冷启动增加 100ms 到 2s 的延迟。
// Lambda execution lifecycle
// INIT PHASE (cold start only)
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const client = new DynamoDBClient({}); // reused across invocations
// INVOKE PHASE (every request)
exports.handler = async (event, context) => {
console.log("Request ID:", context.awsRequestId);
console.log("Time left:", context.getRemainingTimeInMillis(), "ms");
return { statusCode: 200, body: "OK" };
};冷启动因素
| 因素 | 影响 | 缓解 |
|---|---|---|
| 运行时 | Node.js/Python: ~100-200ms, Java: ~1-2s | 选择轻量级运行时 |
| 包大小 | 更大的包增加下载时间 | 摇树优化,使用层 |
| VPC | VPC 附加增加 1-5s | 除非需要否则避免 VPC |
| 内存 | 更多内存 = 更多 CPU = 更快初始化 | 分配 512MB+ 以加快启动 |
Lambda 与 Node.js
Node.js 是最流行的 Lambda 运行时。处理程序接收事件对象和上下文对象。
// index.mjs (ES module handler)
export const handler = async (event, context) => {
const { httpMethod, path, body, queryStringParameters } = event;
try {
const data = JSON.parse(body || "{}");
return {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message: "Success", input: data }),
};
} catch (err) {
return { statusCode: 500, body: JSON.stringify({ error: err.message }) };
}
};Lambda 与 Python
Python 是第二流行的 Lambda 运行时。处理程序模式类似于 Node.js。
# lambda_function.py
import json
import boto3
# Init outside handler (reused on warm starts)
s3 = boto3.client("s3")
def handler(event, context):
body = json.loads(event.get("body", "{}"))
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({"message": "Hello", "input": body})
}API Gateway 集成
API Gateway 提供触发 Lambda 函数的 HTTP 端点,处理路由、请求验证、授权、限流和 CORS。
REST API 配置
使用 Lambda 代理集成时,API Gateway 将整个 HTTP 请求传递给 Lambda。
// API Gateway Lambda Proxy - event structure
// event.httpMethod -> "GET", "POST", etc.
// event.path -> "/users/123"
// event.headers -> { "Content-Type": "..." }
// event.queryStringParameters -> { "page": "1" }
// event.body -> "{...}" (string)
exports.handler = async (event) => {
if (event.httpMethod === "GET" && event.path === "/users") {
return {
statusCode: 200,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify([{ id: 1, name: "Alice" }])
};
}
return { statusCode: 404, body: "Not Found" };
};事件源
Lambda 可由多种 AWS 服务触发,每个事件源提供不同的事件结构。
S3 事件
当 S3 存储桶中的对象被创建、修改或删除时触发 Lambda。
// S3 event handler
exports.handler = async (event) => {
for (const record of event.Records) {
const bucket = record.s3.bucket.name;
const key = decodeURIComponent(record.s3.object.key);
console.log("New object:", bucket, key);
// Process the uploaded file
}
};DynamoDB Streams
实时处理 DynamoDB 表的更改。每个流记录包含旧的和新的项目映像。
// DynamoDB Streams handler
exports.handler = async (event) => {
for (const record of event.Records) {
const { eventName, dynamodb } = record;
if (eventName === "INSERT") {
console.log("New item:", JSON.stringify(dynamodb.NewImage));
} else if (eventName === "MODIFY") {
console.log("Updated:", JSON.stringify(dynamodb.NewImage));
}
}
};SQS
处理 SQS 队列中的消息。Lambda 轮询队列并批量调用函数。
// SQS handler with batch processing
exports.handler = async (event) => {
const failures = [];
for (const record of event.Records) {
try {
const body = JSON.parse(record.body);
await processMessage(body);
} catch (err) {
failures.push({ itemIdentifier: record.messageId });
}
}
return { batchItemFailures: failures };
};Lambda 层和依赖
层让你将库、自定义运行时和配置文件与函数代码分开打包。函数最多可使用 5 个层。
# Create a Lambda Layer
mkdir -p layer/nodejs && cd layer/nodejs
npm init -y
npm install sharp axios
cd ..
zip -r my-layer.zip nodejs/
# Publish the layer
aws lambda publish-layer-version \
--layer-name my-deps \
--zip-file fileb://my-layer.zip \
--compatible-runtimes nodejs20.x
# Attach layer to function
aws lambda update-function-configuration \
--function-name my-func \
--layers arn:aws:lambda:us-east-1:123:layer:my-deps:1环境变量和密钥
使用环境变量进行配置,使用 Parameter Store 或 Secrets Manager 存储敏感值。
// Access env vars and secrets
const { SSMClient, GetParameterCommand } = require("@aws-sdk/client-ssm");
const ssm = new SSMClient({});
// Simple env var (set in Lambda config)
const TABLE = process.env.TABLE_NAME;
// Cached secret from Parameter Store
let dbPassword;
async function getSecret() {
if (!dbPassword) {
const resp = await ssm.send(new GetParameterCommand({
Name: "/myapp/db-password",
WithDecryption: true
}));
dbPassword = resp.Parameter.Value;
}
return dbPassword;
}Lambda 与 DynamoDB
DynamoDB 是 Lambda 最常用的数据库,因为它无缝扩展且具有个位数毫秒延迟。
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const { DynamoDBDocumentClient, PutCommand, GetCommand,
QueryCommand, DeleteCommand } = require("@aws-sdk/lib-dynamodb");
const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({}));
const TABLE = process.env.TABLE_NAME;
exports.handler = async (event) => {
// CREATE
await ddb.send(new PutCommand({
TableName: TABLE,
Item: { pk: "user#1", sk: "profile", name: "Alice" }
}));
// READ
const { Item } = await ddb.send(new GetCommand({
TableName: TABLE, Key: { pk: "user#1", sk: "profile" }
}));
// QUERY
const { Items } = await ddb.send(new QueryCommand({
TableName: TABLE,
KeyConditionExpression: "pk = :pk",
ExpressionAttributeValues: { ":pk": "user#1" }
}));
return { statusCode: 200, body: JSON.stringify(Items) };
};Step Functions
Step Functions 将多个 Lambda 函数编排成工作流,处理重试、错误处理和并行执行。
{
"Comment": "Order processing workflow",
"StartAt": "ValidateOrder",
"States": {
"ValidateOrder": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123:function:validate",
"Next": "ProcessPayment",
"Catch": [{
"ErrorEquals": ["ValidationError"],
"Next": "OrderFailed"
}]
},
"ProcessPayment": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123:function:payment",
"Next": "SendConfirmation"
},
"SendConfirmation": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123:function:notify",
"End": true
},
"OrderFailed": { "Type": "Fail", "Error": "OrderFailed" }
}
}性能优化
Lambda 性能取决于内存分配、包大小和初始化代码。内存与 CPU 能力线性扩展。
预置并发
预热执行环境以消除冷启动。用于延迟敏感的 API。
# Enable provisioned concurrency
aws lambda put-provisioned-concurrency-config \
--function-name my-api \
--qualifier prod \
--provisioned-concurrent-executions 10
# Auto-scale provisioned concurrency
# Use Application Auto Scaling to adjust
# based on utilization (target: 70%)内存调优
Lambda 按内存比例分配 CPU。1769 MB 获得 1 个完整 vCPU。
| 内存 | vCPU | 适用场景 |
|---|---|---|
| 128 MB | 0.07 | 简单路由/代理 |
| 512 MB | 0.29 | API + 数据库查询 |
| 1769 MB | 1.0 | 数据处理/转换 |
| 3008 MB | 1.7 | 图片/视频处理 |
| 10240 MB | 6.0 | ML 推理 |
测试 Lambda 函数
使用 SAM CLI 进行本地测试,使用 AWS SDK 进行集成测试。
# Install SAM CLI
brew install aws-sam-cli
# Invoke locally with test event
sam local invoke MyFunction -e events/api.json
# Start local API Gateway
sam local start-api
# => http://127.0.0.1:3000/users
# Generate sample events
sam local generate-event s3 put \
--bucket my-bucket --key test.txt > events/s3.json
# Run unit tests (Jest example)
# test/handler.test.js
# const { handler } = require("../index");
# test("returns 200", async () => {
# const event = { httpMethod: "GET", path: "/users" };
# const result = await handler(event);
# expect(result.statusCode).toBe(200);
# });使用 SAM 的基础设施即代码
AWS SAM 用无服务器特定资源类型扩展 CloudFormation。
# template.yaml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Timeout: 30
Runtime: nodejs20.x
MemorySize: 512
Resources:
ApiFunction:
Type: AWS::Serverless::Function
Properties:
Handler: src/index.handler
Events:
GetUsers:
Type: Api
Properties:
Path: /users
Method: get
Environment:
Variables:
TABLE_NAME: !Ref UsersTable
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref UsersTable
UsersTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: users
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: pk
AttributeType: S
KeySchema:
- AttributeName: pk
KeyType: HASH监控和调试
Lambda 与 CloudWatch 集成用于日志和指标,与 X-Ray 集成用于分布式追踪。
CloudWatch 指标
Lambda 发出调用次数、持续时间、错误、限流和并发执行的指标。
// Structured logging for CloudWatch
exports.handler = async (event, context) => {
console.log(JSON.stringify({
level: "INFO",
requestId: context.awsRequestId,
message: "Processing request",
path: event.path,
method: event.httpMethod
}));
// CloudWatch Embedded Metric Format
console.log(JSON.stringify({
_aws: { Timestamp: Date.now(),
CloudWatchMetrics: [{
Namespace: "MyApp",
Dimensions: [["Function"]],
Metrics: [{ Name: "ProcessingTime", Unit: "Milliseconds" }]
}]
},
Function: context.functionName,
ProcessingTime: 42
}));
};X-Ray 追踪
X-Ray 跨 Lambda、API Gateway、DynamoDB 追踪请求。在函数配置中启用主动追踪。
# Enable X-Ray tracing via CLI
aws lambda update-function-configuration \
--function-name my-func \
--tracing-config Mode=Active
# SAM template
# Properties:
# Tracing: Active
# In code: wrap AWS SDK calls for tracing
# const AWSXRay = require("aws-xray-sdk-core");
# const AWS = AWSXRay.captureAWS(require("aws-sdk"));Lambda 限制和配额
了解 Lambda 限制有助于设计在服务边界内的函数。以下是最常遇到的限制。
| 资源 | 默认限制 | 可调整 |
|---|---|---|
| 并发执行 | 每区域 1,000 | 是(最高数万) |
| 超时 | 15 分钟(900 秒) | 否(硬限制) |
| 内存 | 128 MB 到 10,240 MB | 否 |
| 部署包(zip) | 直接上传 50 MB,解压 250 MB | 否(使用容器镜像) |
| 临时存储(/tmp) | 512 MB 到 10,240 MB | 可配置 |
| 环境变量大小 | 总共 4 KB | 否 |
| 每函数层数 | 5 | 否 |
错误处理模式
正确的错误处理对 Lambda 可靠性至关重要。同步调用(API Gateway)和异步调用(S3、SNS)的处理方式不同。同步返回结构化错误响应,异步配置死信队列和 Lambda 目标。
// Robust error handling pattern
class AppError extends Error {
constructor(message, statusCode, errorCode) {
super(message);
this.statusCode = statusCode;
this.errorCode = errorCode;
}
}
exports.handler = async (event, context) => {
try {
const result = await processRequest(event);
return {
statusCode: 200,
body: JSON.stringify(result)
};
} catch (err) {
console.error(JSON.stringify({
level: "ERROR",
requestId: context.awsRequestId,
error: err.message,
code: err.errorCode || "INTERNAL_ERROR"
}));
const statusCode = err.statusCode || 500;
return {
statusCode,
body: JSON.stringify({
error: err.errorCode || "INTERNAL_ERROR",
message: statusCode < 500 ? err.message : "Internal error"
})
};
}
};部署最佳实践
使用别名和版本进行安全部署。Lambda 版本是函数代码和配置的不可变快照。别名是指向版本的指针,支持流量转移和回滚。
- 开发使用 $LATEST,暂存/生产使用编号版本
- 创建别名(dev、staging、prod)指向特定版本
- 使用加权别名进行金丝雀部署(90% v1, 10% v2)
- 启用 CodeDeploy 钩子进行流量转移前后验证
- 将 API Gateway 阶段绑定到 Lambda 别名,而非 $LATEST
- 使用 SAM 管道或 GitHub Actions 自动化部署
# Publish a new version
aws lambda publish-version --function-name my-func
# Create/update alias pointing to version 5
aws lambda create-alias \
--function-name my-func \
--name prod --function-version 5
# Canary deployment: shift 10% traffic to v6
aws lambda update-alias \
--function-name my-func \
--name prod --function-version 6 \
--routing-config AdditionalVersionWeights={"5"=0.9}常见问题
Lambda 的最大执行时间是多少?
Lambda 函数最多可运行 15 分钟。对于更长的工作负载,使用 Step Functions 或 ECS/Fargate。
AWS Lambda 费用多少?
按请求(每百万 $0.20)和每 GB 秒收费。免费层每月包含 100 万请求。
如何减少冷启动时间?
使用轻量级运行时,最小化包大小,避免不必要的 VPC,分配更多内存,使用预置并发。
Lambda 能连接关系数据库吗?
可以,但使用 RDS Proxy 管理连接池。否则 Lambda 可能耗尽数据库连接。
最大部署包大小是多少?
直接上传 50 MB(压缩),含层 250 MB(解压)。容器镜像最大 10 GB。
Lambda 层如何工作?
层是包含库的 ZIP 归档,提取到 /opt。函数最多引用 5 个层。
同步和异步调用有什么区别?
同步调用等待完成并返回结果。异步调用将事件入队并立即返回。
如何处理 Lambda 中的错误?
同步调用返回 HTTP 状态码。异步调用配置死信队列或 Lambda 目标。使用结构化日志调试。