⚡ 第21课:Serverless

核心概念

Serverless:让服务器消失

Serverless让开发者只关注代码,无需管理服务器。按调用次数付费,自动弹性伸缩。

Serverless平台对比

平台           │ 运行时              │ 冷启动  │ 免费额度        │ 最大时长
───────────────┼─────────────────────┼────────┼────────────────┼────────
AWS Lambda     │ Node/Python/Java等 │ ~100ms │ 100万调用/月   │ 15min
Azure Func     │ 同上+C#            │ ~200ms │ 100万调用/月   │ 10min
阿里云FC       │ Node/Python/Java等 │ ~150ms │ 100万调用/月   │ 10min
腾讯云SCF      │ Node/Python/Go等   │ ~150ms │ 100万调用/月   │ 15min
Cloudflare Wkr │ JS/Rust/WASM       │ ~0ms   │ 10万请求/天   │ 30s

命令实操

1. AWS Lambda函数开发 ✅

Lambda开发
cat > handler.py << 'EOF'
import json, boto3

def lambda_handler(event, context):
    method = event.get('httpMethod', 'GET')
    path = event.get('path', '/')
    
    if method == 'GET' and path == '/health':
        return {'statusCode': 200, 'body': json.dumps({'status': 'healthy'})}
    
    if method == 'POST' and path == '/deploy':
        body = json.loads(event.get('body', '{}'))
        env = body.get('environment', 'staging')
        ecs = boto3.client('ecs')
        ecs.update_service(cluster=f'myapp-{env}', service='myapp', force_new_deployment=True)
        return {'statusCode': 200, 'body': json.dumps({'message': f'Deployed to {env}'})}
    return {'statusCode': 404, 'body': json.dumps({'error': 'Not found'})}
EOF

zip function.zip handler.py
aws lambda create-function --function-name devops-deploy-trigger \
    --runtime python3.12 --handler handler.lambda_handler \
    --role arn:aws:iam::123:role/lambda-exec-role --zip-file fileb://function.zip

# 测试
aws lambda invoke --function-name devops-deploy-trigger \
    --payload '{"httpMethod":"GET","path":"/health"}' response.json

2. Serverless Framework ✅

Serverless Framework
npm install -g serverless
serverless create --template aws-python --path my-devops-api
cd my-devops-api

cat > serverless.yml << 'EOF'
service: devops-api
frameworkVersion: "3"
provider:
  name: aws
  runtime: python3.12
  region: ap-southeast-1
  stage: ${opt:stage, 'dev'}
  iamRoleStatements:
    - Effect: Allow
      Action: [ecs:UpdateService, ecs:DescribeServices]
      Resource: "*"
functions:
  health:
    handler: handler.health
    events: [{http: {path: /health, method: get, cors: true}}]
  deploy:
    handler: handler.deploy
    events: [{http: {path: /deploy, method: post, cors: true}}]
  backup:
    handler: handler.backup
    events: [{schedule: cron(0 2 * * ? *)}]
    timeout: 300
EOF

serverless deploy --stage prod
serverless info

3. 阿里云函数计算 ✅

阿里云FC
npm install -g @alicloud/fun
fun init -n devops-deploy python3

cat > template.yml << 'EOF'
ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
  devops-service:
    Type: 'Aliyun::Serverless::Service'
    deploy-function:
      Type: 'Aliyun::Serverless::Function'
      Properties:
        Handler: index.handler
        Runtime: python3.9
        CodeUri: ./
        Timeout: 60
        MemorySize: 256
      Events:
        http-trigger:
          Type: HTTP
          Properties: {AuthType: ANONYMOUS, Methods: ['POST']}
EOF
fun deploy -y

架构图

Serverless:让服务器消失架构

┌──────────┐  ┌──────────┐  ┌──────────┐
│ API GW   │  │  定时触发 │  │ 事件触发  │
│ (HTTP)   │  │ (Cron)   │  │ (S3/SQS) │
└────┬─────┘  └────┬─────┘  └────┬─────┘
     └──────────────┼──────────────┘
                    ▼
           ┌────────────────┐
           │  Lambda/FC     │
           │  (自动弹性)    │
           └───────┬────────┘
    ┌──────────────┼──────────────┐
    ▼              ▼              ▼
┌────────┐  ┌──────────┐  ┌──────────┐
│ DynamoDB│ │  S3/OSS  │  │  ECS/K8s │
│ (状态)  │ │  (存储)   │ │  (操作)   │
└────────┘  └──────────┘  └──────────┘

故障排查

❌ Lambda冷启动慢

排查
# Provisioned Concurrency(预置并发)
aws lambda put-provisioned-concurrency-config \
    --function-name devops-deploy-trigger \
    --provisioned-concurrent-executions 5

# 减小部署包
pip install --target=./package -r requirements.txt
cd package && zip -r ../function.zip . && cd .. && zip -g function.zip handler.py

# 选择轻量运行时(Node/Python > Java)
💡 Serverless最佳实践:保持函数小而快、使用预置并发消除冷启动、避免在handler中初始化重资源。

🏆 成就解锁:Serverless专家!

掌握Lambda/FC开发、Serverless Framework、冷启动优化——无服务器是云原生未来

📝 Serverless适用场景

场景适合不适合
API后端✅ 低延迟请求❌ 长连接WebSocket
数据处理✅ ETL/转换❌ 大数据批处理
定时任务✅ 轻量cron❌ 长时间运行任务
事件驱动✅ S3上传触发❌ 需要本地状态
Webhook✅ GitHub/Slack❌ 高QPS实时处理
💡 Serverless省钱技巧:合并细粒度函数减少冷启动、使用Provisioned Concurrency消除冷启动、合理设置内存(内存↑→CPU↑→执行时间↓→费用↓)。

🔧 Serverless监控与调试

Lambda调试
# 本地调试Lambda
npm install -g serverless-offline
serverless offline --port 3000

# 查看Lambda指标
aws cloudwatch get-metric-statistics \
    --namespace AWS/Lambda \
    --metric-name Duration \
    --dimensions Name=FunctionName,Value=devops-deploy-trigger \
    --start-time $(date -d '1 hour ago' -Is) \
    --end-time $(date -Is) --period 60 --statistics Average

# X-Ray分布式追踪
aws lambda update-function-configuration \
    --function-name devops-deploy-trigger \
    --tracing-config {Mode: Active}

# 查看X-Ray追踪
aws xray get-traces --start-time $(date -d '1 hour ago' +%s)
⚠️ Serverless陷阱:冷启动、执行时长限制、调试困难、厂商锁定。不要把所有服务都无服务器化。

🔧 Serverless成本计算器

成本估算
#!/bin/bash
# serverless-cost-estimate.sh
# Lambda定价: $0.0000002/请求 + $0.0000166667/GB-秒

REQUESTS=${1:-1000000}       # 月请求数
AVG_DURATION=${2:-200}      # 平均执行时间(ms)
MEMORY=${3:-256}            # 内存(MB)

# 计算费用
REQUEST_COST=$(echo "$REQUESTS * 0.0000002" | bc)
GB_SECONDS=$(echo "$REQUESTS * $AVG_DURATION / 1000 * $MEMORY / 1024" | bc)
COMPUTE_COST=$(echo "$GB_SECONDS * 0.0000166667" | bc)
TOTAL=$(echo "$REQUEST_COST + $COMPUTE_COST" | bc)

echo "╔════════════════════════════════════════╗"
echo "║     Lambda月度成本估算                 ║"
echo "╠════════════════════════════════════════╣"
printf "║ 请求数:     %-28s║\n" "$REQUESTS"
printf "║ 平均耗时:   %-28s║\n" "${AVG_DURATION}ms"
printf "║ 内存配置:   %-28s║\n" "${MEMORY}MB"
printf "║ 请求费用:   \$%-27s║\n" "$REQUEST_COST"
printf "║ 计算费用:   \$%-27s║\n" "$COMPUTE_COST"
printf "║ 月总费用:   \$%-27s║\n" "$TOTAL"
echo "╚════════════════════════════════════════╝"

# 与EC2对比
EC2_MONTHLY=30  # t3.medium月费
echo "对比: t3.medium EC2月费 \$$EC2_MONTHLY"
echo "Lambda更经济的条件: 月请求<$(echo "$EC2_MONTHLY / $TOTAL * $REQUESTS" | bc)"

Serverless适用

传统服务适用