引言
Serverless架构通过按需执行和自动扩缩容,让开发者专注于业务逻辑而无需管理基础设施。结合边缘计算技术,可以将计算推向离用户更近的位置,显著降低延迟。
本文将介绍Serverless与边缘计算的核心概念、设计模式和实战案例。
Serverless架构模式
Function as a Service(FaaS)
FaaS是Serverless的核心,以函数为单位执行代码。
// AWS Lambda 函数示例
exports.handler = async (event) => {
const { userId, action } = JSON.parse(event.body);
try {
let result;
switch (action) {
case 'getUser':
result = await userService.getUser(userId);
break;
case 'updateUser':
result = await userService.updateUser(userId, event.body);
break;
default:
return {
statusCode: 400,
body: JSON.stringify({ error: 'Invalid action' })
};
}
return {
statusCode: 200,
body: JSON.stringify(result),
headers: {
'Content-Type': 'application/json'
}
};
} catch (error) {
console.error('Error:', error);
return {
statusCode: 500,
body: JSON.stringify({ error: 'Internal server error' })
};
}
};
事件驱动架构
Serverless函数由事件触发,形成松耦合的系统。
# AWS SAM 模板
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
# API Gateway触发
GetUserFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs18.x
Events:
GetApi:
Type: Api
Properties:
Path: /users/{userId}
Method: GET
# S3事件触发
ImageProcessorFunction:
Type: AWS::Serverless::Function
Properties:
Handler: processor.handler
Runtime: nodejs18.x
Events:
S3Upload:
Type: S3
Properties:
Bucket: !Ref ImageBucket
Events: s3:ObjectCreated:*
# SQS消息触发
OrderProcessorFunction:
Type: AWS::Serverless::Function
Properties:
Handler: order.handler
Runtime: nodejs18.x
Events:
SQSEvent:
Type: SQS
Properties:
Queue: !GetAtt OrderQueue.Arn
BatchSize: 10
编排与协调
使用Step Functions编排多个Serverless函数。
# AWS Step Functions 工作流
Comment: "订单处理工作流"
StartAt: ValidateOrder
States:
ValidateOrder:
Type: Task
Resource: arn:aws:lambda:region:account:function:validateOrder
Next: CheckInventory
Catch:
- ErrorEquals: ["ValidationError"]
Next: OrderFailed
CheckInventory:
Type: Task
Resource: arn:aws:lambda:region:account:function:checkInventory
Next: HasInventory
Catch:
- ErrorEquals: ["InventoryError"]
Next: OrderFailed
HasInventory:
Type: Choice
Choices:
- Variable: "$.available"
BooleanEquals: true
Next: ProcessPayment
Default: OrderFailed
ProcessPayment:
Type: Task
Resource: arn:aws:lambda:region:account:function:processPayment
Next: ShipOrder
Catch:
- ErrorEquals: ["PaymentError"]
Next: OrderFailed
ShipOrder:
Type: Task
Resource: arn:aws:lambda:region:account:function:shipOrder
Next: OrderSuccess
OrderSuccess:
Type: Succeed
OrderFailed:
Type: Fail
Error: "OrderProcessingFailed"
边缘计算架构
Cloudflare Workers
在全球边缘节点执行代码,延迟极低。
// Cloudflare Worker 示例
export default {
async fetch(request, env) {
const url = new URL(request.url);
// 边缘缓存策略
const cacheKey = new Request(url.toString(), request);
const cache = caches.default;
let response = await cache.match(cacheKey);
if (!response) {
// 从源站获取
response = await fetch(request);
// 缓存响应(仅对GET请求)
if (request.method === 'GET' && response.status === 200) {
const cacheResponse = response.clone();
cacheResponse.headers.set('Cache-Control', 'public, max-age=3600');
await cache.put(cacheKey, cacheResponse);
}
}
// 边缘A/B测试
const variant = getVariant(request);
response = new Response(response.body, response);
response.headers.set('X-Variant', variant);
return response;
}
};
function getVariant(request) {
// 基于用户特征分配测试组
const userId = request.headers.get('CF-Connecting-IP');
const hash = simpleHash(userId);
return hash % 2 === 0 ? 'A' : 'B';
}
function simpleHash(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash = ((hash << 5) - hash) + str.charCodeAt(i);
hash = hash & hash;
}
return Math.abs(hash);
}
边缘数据处理
在边缘节点执行数据过滤和转换,减少回源流量。
// 边缘图像处理
export default {
async fetch(request, env) {
const url = new URL(request.url);
// 解析图像转换参数
const width = url.searchParams.get('w');
const height = url.searchParams.get('h');
const format = url.searchParams.get('format') || 'webp';
// 从源站获取原图
const originUrl = `https://origin.example.com${url.pathname}`;
const response = await fetch(originUrl);
if (!response.ok) {
return response;
}
// 在边缘转换图像
const transformedImage = await env.IMAGE_RESIZER.resize(
await response.arrayBuffer(),
{
width: parseInt(width),
height: parseInt(height),
format: format
}
);
return new Response(transformedImage, {
headers: {
'Content-Type': `image/${format}`,
'Cache-Control': 'public, max-age=31536000'
}
});
}
};
冷启动优化
预热策略
// 定时预热Lambda函数
exports.warmer = async (event) => {
console.log('Warm-up invocation at:', new Date().toISOString());
return { statusCode: 200, body: 'Warmed up' };
};
// CloudWatch Events 规则
// 每5分钟触发一次预热
{
"schedule": "rate(5 minutes)",
"input": {
"type": "warmup"
}
}
包大小优化
// 使用Lambda Layers共享依赖
// layer/nodejs/node_modules/ 包含公共依赖
// 函数代码只包含特定依赖
const { DynamoDB } = require('@aws-sdk/client-dynamodb');
exports.handler = async (event) => {
const client = new DynamoDB({});
// 业务逻辑
};
# SAM模板配置Layer
Resources:
CommonLayer:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: common-dependencies
ContentUri: layers/common/
CompatibleRuntimes:
- nodejs18.x
MyFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs18.x
Layers:
- !Ref CommonLayer
连接池复用
// 数据库连接池复用
const { Pool } = require('pg');
// 在函数外部创建连接池(跨调用复用)
let pool;
if (!pool) {
pool = new Pool({
host: process.env.DB_HOST,
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
max: 10,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000
});
}
exports.handler = async (event) => {
const client = await pool.connect();
try {
const result = await client.query('SELECT * FROM users WHERE id = $1', [event.userId]);
return {
statusCode: 200,
body: JSON.stringify(result.rows[0])
};
} finally {
client.release();
}
};
Knative:Kubernetes上的Serverless
服务定义
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: user-service
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/minScale: "1"
autoscaling.knative.dev/maxScale: "10"
autoscaling.knative.dev/target: "100" # 目标并发数
spec:
containers:
- image: gcr.io/my-project/user-service:latest
ports:
- containerPort: 8080
env:
- name: DB_HOST
valueFrom:
secretKeyRef:
name: db-secret
key: host
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
事件触发
# Kafka事件源
apiVersion: sources.knative.dev/v1beta1
kind: KafkaSource
metadata:
name: order-events
spec:
consumerGroup: order-processor
bootstrapServers:
- kafka-broker:9092
topics:
- orders
sink:
ref:
apiVersion: serving.knative.dev/v1
kind: Service
name: order-processor
性能优化策略
异步处理
// 使用队列异步处理耗时任务
exports.handler = async (event) => {
const { orderId, userId } = JSON.parse(event.body);
// 快速响应,将任务放入队列
await sqs.sendMessage({
QueueUrl: process.env.ORDER_QUEUE_URL,
MessageBody: JSON.stringify({ orderId, userId })
}).promise();
return {
statusCode: 202,
body: JSON.stringify({
message: 'Order accepted',
orderId: orderId
})
};
};
// 异步处理函数
exports.processor = async (event) => {
for (const record of event.Records) {
const { orderId, userId } = JSON.parse(record.body);
try {
await processOrder(orderId, userId);
} catch (error) {
// 发送到死信队列
await sqs.sendMessage({
QueueUrl: process.env.DLQ_URL,
MessageBody: record.body
}).promise();
}
}
};
缓存策略
// Redis缓存(使用Upstash等服务)
const redis = require('redis');
let client;
async function getRedisClient() {
if (!client) {
client = redis.createClient({
url: process.env.REDIS_URL
});
await client.connect();
}
return client;
}
exports.handler = async (event) => {
const { productId } = event.pathParameters;
const cacheKey = `product:${productId}`;
const redis = await getRedisClient();
// 尝试从缓存获取
let product = await redis.get(cacheKey);
if (!product) {
// 缓存未命中,查询数据库
product = await db.getProduct(productId);
// 写入缓存(TTL 1小时)
await redis.setEx(cacheKey, 3600, JSON.stringify(product));
} else {
product = JSON.parse(product);
}
return {
statusCode: 200,
body: JSON.stringify(product)
};
};
成本优化
内存与执行时间平衡
// 性能测试脚本
const testConfigurations = [
{ memory: 128, description: '128MB' },
{ memory: 256, description: '256MB' },
{ memory: 512, description: '512MB' },
{ memory: 1024, description: '1GB' }
];
async function benchmark(memorySize) {
const startTime = Date.now();
// 执行Lambda函数
const result = await lambda.invoke({
FunctionName: 'my-function',
Qualifier: `$LATEST`,
Payload: JSON.stringify(testPayload)
}).promise();
const duration = Date.now() - startTime;
const cost = calculateCost(memorySize, result.Payload.Duration);
return {
memorySize,
duration,
cost,
costPerRequest: cost / 1000000 // 每百万请求成本
};
}
批处理优化
// 批量处理SQS消息
exports.handler = async (event) => {
const records = event.Records;
// 批量查询数据库
const userIds = records.map(r => JSON.parse(r.body).userId);
const users = await db.getUsersByIds(userIds);
// 批量处理
const results = await Promise.all(records.map(async (record, index) => {
const user = users[index];
return processUser(user);
}));
// 返回批处理结果
return {
batchItemFailures: results
.map((r, i) => r.success ? null : { itemIdentifier: records[i].messageId })
.filter(Boolean)
};
};
边缘数据持久化与状态管理
Serverless 函数默认无状态,但在实际业务中常需要跨请求保持状态:
// Durable Objects:Cloudflare 的状态化边缘计算
export class Counter {
constructor(state, env) {
this.state = state;
}
async fetch(request) {
// 当前请求可以通过 storage 持久化状态
let url = new URL(request.url);
let current = (await this.state.storage.get("value")) || 0;
switch (url.pathname) {
case "/increment":
current++;
await this.state.storage.put("value", current);
return new Response(JSON.stringify({value: current}));
case "/decrement":
current--;
await this.state.storage.put("value", current);
return new Response(JSON.stringify({value: current}));
default:
return new Response(JSON.stringify({value: current}));
}
}
}
// wrangler.toml 配置
[[ durable_objects.bindings ]]
name = "COUNTER"
class_name = "Counter"
| 状态持久化方案 | 延迟 | 一致性 | 适用场景 | 云厂商支持 |
|---|---|---|---|---|
| DynamoDB | 10-20ms | 最终一致/强一致 | 用户会话、计数器 | AWS |
| Firebase/Firestore | < 10ms | 最终一致 | 实时游戏状态、聊天 | GCP |
| Cloudflare D1 | < 50ms | SQLite 事务 | 边缘关系数据查询 | Cloudflare |
| Edge Redis | < 5ms | 最终一致 | 缓存、排行榜、限流 | Upstash/Dragonfly |
| Durable Objects | < 50ms | 强一致 | WebSocket、协作编辑 | Cloudflare |
边缘 Serverless 网关模式
// Cloudflare Worker 作为 BFF(Backend for Frontend)网关
export default {
async fetch(request, env) {
const url = new URL(request.url);
const clientType = request.headers.get('X-Client-Type'); // web/ios/android
// 统一认证:验证 JWT
const authResult = await verifyJWT(request);
if (!authResult.valid) {
return new Response('Unauthorized', {status: 401});
}
// 根据客户端类型聚合不同后端服务的响应
const handlers = {
'web': () => aggregateWebResponse(url, authResult.userId),
'ios': () => aggregateMobileResponse(url, authResult.userId, 'ios'),
'android': () => aggregateMobileResponse(url, authResult.userId, 'android')
};
const response = await handlers[clientType]();
// 边缘缓存:相同查询缓存 60 秒
response.headers.set('Cache-Control', 'public, max-age=60');
response.headers.set('CDN-Cache-Control', 'max-age=300');
return response;
}
};
// 缓存侧聚合:减少客户端请求数
async function aggregateWebResponse(url, userId) {
const [profile, notifications, recommendations] = await Promise.all([
fetch(`${USER_API}/users/${userId}`),
fetch(`${NOTIFY_API}/notifications/${userId}?unread=true`),
fetch(`${REC_API}/recommendations/${userId}`)
]);
return new Response(JSON.stringify({
profile: await profile.json(),
notifications: await notifications.json(),
recommendations: await recommendations.json()
}), {
headers: {'Content-Type': 'application/json'}
});
}
网关 vs 直连对比
直连模式: 网关模式:
┌────────────┐
│ Edge GW │
│ (认证/聚合) │
Client ──► 服务A Client ──►────┴────────► 服务A
──► 服务B
──► 服务C ──► 服务B(通过网关转发)
──► 服务D ──► 服务C
问题: 优势:
- N次RTT - 1次RTT到边缘
- 客户端复杂 - 统一认证/协议转换
- 暴露内部 API - 内部服务不暴露公网
- 缓存控制分散 - 边缘统一管理缓存策略
平台功能对比
| 能力 | AWS Lambda | Cloudflare Workers | Vercel Edge | Deno Deploy |
|---|---|---|---|---|
| 运行环境 | Firecracker VM | V8 Isolate | Node.js Edge Runtime | Deno Runtime |
| 冷启动 | 100ms-1s | 0ms | 0-50ms | 0ms |
| 单请求 CPU 时间 | 15 min | 50ms (CPU time) | 30s | 无明确限制 |
| 内存 | 128MB-10GB | 128MB | 1GB | 512MB |
| 支持语言 | 全部 | JS/TS/Rust/Wasm | JS/TS/Go | JS/TS |
| 边缘节点 | 30+ Region | 300+ City | 100+ Edge | 35+ Region |
| 本地存储 | /tmp 512MB | KV/DO/D1 | KV | KV |
| 定价模型 | 请求 + 持续时间 | 请求数 + CPU | 请求 + 带宽 | 请求 + 带宽 |
| WebSocket | 通过 API Gateway | Durable Objects | 实验性 | 原生支持 |
// Platform-agnostic 封装(可在 Lambda/Worker/Edge 间迁移)
export default {
async fetch(request, env, ctx) {
// env 包含绑定(KV、D1、Secret)
// ctx 包含执行上下文(waitUntil 用于异步任务)
const cache = caches.default;
const cached = await cache.match(request);
if (cached) return cached;
const result = await handleRequest(request, env);
ctx.waitUntil(cache.put(request, result.clone()));
return result;
}
};
// AWS Lambda 适配层
export const handler = async (event, context) => {
const request = convertLambdaEventToRequest(event);
const response = await fetch(request);
return convertResponseToLambdaResult(response);
};
总结
Serverless与边缘计算为构建现代分布式系统提供了强大的工具:
- Serverless:按需执行、自动扩缩容、降低运维成本
- 边缘计算 :全球分布、低延迟、减轻源站压力
- 冷启动优化:预热、包优化、连接池复用、分层 JAR
- 性能优化:异步处理、缓存、批处理、连接复用
- 状态管理:Durable Objects、边缘 KV、D1 SQLite 持久化
- 网关模式:边缘 BFF 聚合、统一认证、缓存控制
| 场景 | 推荐方案 | 关键考量 |
|---|---|---|
| 事件驱动任务 | AWS Lambda + S3/SQS | 触发器丰富,成熟生态 |
| API 网关/聚合 | Cloudflare Workers | 全球 300+ 节点,延迟极低 |
| Next.js 全栈 | Vercel Edge | 与框架深度集成 |
| 实时 WebSocket | Cloudflare Durable Objects | 状态化长连接 |
| 边缘关系查询 | Cloudflare D1 | SQLite API,近零延迟 |
| 高并发无状态 API | Knative on K8s | 自动扩缩 + 成本控制 |
不适合:长时间运行的进程(>15min)、有状态服务(需 Durable Objects 替代)、高性能计算(需 GPU 实例)。
延伸阅读
- AWS Lambda Best Practices
- Cloudflare Workers Documentation
- Knative Documentation
- Serverless Framework
- Vercel Edge Runtime
- Deno Deploy Documentation
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。