Chapter 10

可观测与生产部署

能跑不等于能上线。本章把从"本地 dev"到"百万 QPS 线上服务"的最后一公里讲清:日志、追踪、指标、多环境 secrets、CI/CD、回滚——每一个都踩过坑。

三层可观测

┌──────────────────────────────────────────┐ │ Logs:每次请求的 stdout / stderr │ → wrangler tail、Logpush ├──────────────────────────────────────────┤ │ Metrics:QPS、延迟、错误率、CPU 用量 │ → Dashboard Analytics ├──────────────────────────────────────────┤ │ Events:业务自定义计数、漏斗、留存 │ → Analytics Engine └──────────────────────────────────────────┘

Logs:实时 Tail 与 Logpush

# 实时看当前流量
wrangler tail

# JSON 格式 + 过滤
wrangler tail --format json --status error --method POST

# 指定环境
wrangler tail --env production --format pretty

tail 适合实时排错。长期存储用 Logpush——把日志推到 R2 / Datadog / Splunk / BigQuery:

wrangler logpush create \
  --dataset workers_trace_events \
  --destination "r2://my-logs/traces?account-id=..."

Tail Workers:程序化日志处理

写一个专门的 Worker 接收其他 Worker 的日志,做过滤、聚合、告警:

[tail_consumers]
service = "log-processor"
// log-processor Worker
export default {
  async tail(events: TraceItem[], env: Env) {
    for (const e of events) {
      if (e.outcome === 'exception') {
        await sendToSentry(env, e);
      }
      if (e.scriptName === 'payment-api' && e.event.response?.status >= 500) {
        await pageOncall(env, e);
      }
    }
  },
};

Analytics Engine:业务指标

每个事件一行,后台自动聚合,SQL 查询——自己写的轻量 BigQuery。

[[analytics_engine_datasets]]
binding = "ANALYTICS"
dataset = "api_usage"
app.use('*', async (c, next) => {
  const start = Date.now();
  await next();
  c.env.ANALYTICS.writeDataPoint({
    blobs: [c.req.path, c.req.header('user-agent') ?? ''],
    doubles: [Date.now() - start, c.res.status],
    indexes: [c.env.ENV],  // 分区键
  });
});
-- Dashboard SQL 查询
SELECT blob1 AS path, quantileMerge(0.95)(double1) AS p95_ms, count()
FROM api_usage
WHERE timestamp > now() - INTERVAL '1' HOUR
GROUP BY path
ORDER BY p95_ms DESC
LIMIT 20;

错误捕获

app.onError((err, c) => {
  console.error('[error]', err.stack, {
    path: c.req.path,
    reqId: c.req.header('cf-ray'),
  });
  // Sentry/Baselime 发送
  return c.json({ error: 'internal', reqId: c.req.header('cf-ray') }, 500);
});

cf-ray 是 Cloudflare 给每个请求的唯一 ID,写进响应,日志里也有——用户报错时让他贴 Ray ID 就能定位。

多环境 + Secrets

name = "my-api"
main = "src/index.ts"

[vars]
ENV = "development"

[env.staging.vars]
ENV = "staging"
[[env.staging.d1_databases]]
binding = "DB"
database_id = "staging-db-id"

[env.production.vars]
ENV = "production"
[[env.production.d1_databases]]
binding = "DB"
database_id = "prod-db-id"
wrangler secret put STRIPE_KEY --env staging
wrangler secret put STRIPE_KEY --env production

wrangler deploy --env staging
wrangler deploy --env production

CI/CD with GitHub Actions

# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]

jobs:
  test-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm ci
      - run: npm test
      - run: npm run typecheck

      # 先部署到 staging
      - name: Deploy staging
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CF_API_TOKEN }}
          command: deploy --env staging

      # 跑 smoke tests
      - run: npm run test:e2e -- --url https://staging.example.com

      # 通过后再推生产
      - name: Deploy production
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CF_API_TOKEN }}
          command: deploy --env production

Gradual Deployment:灰度

Cloudflare 支持一个 Worker 的不同 version 按百分比分流:

# 部署但不激活
wrangler versions upload

# 让新版本接管 10%
wrangler versions deploy --percentage=10

# 观察指标,逐步提升
wrangler versions deploy --percentage=50
wrangler versions deploy --percentage=100

回滚

wrangler deployments list
# 显示所有历史部署和版本号

wrangler rollback --version-id=xxxxx
# 秒级切回上一个稳定版本

比 Vercel/Netlify 的回滚更快——因为 Workers 的所有历史版本都保留在边缘,切换只是改路由。

上生产检查单

安全基线

Turnstile
Cloudflare 的 CAPTCHA 替代,无感验证挡机器人。登录、注册、评论表单都值得加。
WAF Rules
免费 Managed Rules 防 SQLi/XSS/已知 CVE。自定义 Rules 可按 header/cookie/path 拦截。
Rate Limiting
原生 Rate Limiting Rules 按 IP / header 限速。也可以用 DO 做精细化(见第 6 章)。
Zero Trust Access
内部工具类路径挂 Access,只允许特定身份(Google Workspace / OIDC)访问。

终点

走到这里,你拥有一套完整的边缘全栈认知:用 Workers 承流量,用 D1 / R2 / KV 存数据,用 DO 做有状态,用 Queue / Cron / Workflows 做异步,用 Workers AI / Vectorize 做 RAG,用 Logs / Analytics Engine / Gradual Deploy 保运维。

下一步实战:

全书小结