发布与上线
概述
带着信心发布。目标不仅仅是部署——而是安全地部署,监控到位,回滚计划就绪,并对成功的标准有清晰的理解。每次发布都应该是可逆的、可观测的,并且是增量的。
何时使用
- 首次将功能部署到生产环境
- 向用户发布重大变更
- 迁移数据或基础设施
- 开启 Beta 版或早期访问计划
- 任何有风险的部署(所有部署都有风险)
预发布检查清单
代码质量
- 所有测试通过(单元测试、集成测试、端到端测试)
- 构建成功,无警告
- Lint 和类型检查通过
- 代码已审查并批准
- 没有应在发布前解决的 TODO 注释
- 生产代码中没有
console.log调试语句 - 错误处理涵盖了预期的故障模式
安全性
- 代码或版本控制中没有密钥
- 生态系统的依赖审计(
npm audit,pip-audit,cargo audit, ...)未发现严重或高危漏洞 - 所有面向用户的端点都有输入验证
- 身份验证和授权检查已就位
- 安全头已配置(CSP, HSTS 等)
- 认证端点已启用速率限制
- CORS 已配置为特定源(非通配符)
性能
- 核心 Web 指标在“良好”阈值内
- 关键路径中没有 N+1 查询
- 图片已优化(压缩、响应式尺寸、懒加载)
- 打包体积在预算内
- 数据库查询有适当的索引
- 为静态资源和重复查询配置了缓存
无障碍
- 所有交互元素的键盘导航有效
- 屏幕阅读器可以传达页面内容和结构
- 颜色对比度符合 WCAG 2.1 AA 标准(文本 4.5:1)
- 模态框和动态内容的焦点管理正确
- 错误消息具有描述性并与表单字段关联
- axe-core 或 Lighthouse 中无无障碍警告
基础设施
- 生产环境的环境变量已设置
- 数据库迁移已应用(或准备应用)
- DNS 和 SSL 已配置
- CDN 已为静态资源配置
- 日志记录和错误报告已配置
- 健康检查端点存在并能响应
文档
- README 已更新,包含任何新的设置要求
- API 文档是最新的
- 已为任何架构决策编写 ADR
- 更新了变更日志
- 面向用户的文档已更新(如适用)
功能标志策略
在功能标志后发布,将部署与发布解耦:
// 功能标志检查
const flags = await getFeatureFlags(userId);
if (flags.taskSharing) {
// 新功能:任务共享
return <TaskSharingPanel task={task} />;
}
// 默认:现有行为
return null;
功能标志生命周期:
1. 部署时标志为 OFF → 代码在生产环境但未激活
2. 为团队/Beta 版启用 → 在生产环境进行内部测试
3. 逐步发布 → 5% → 25% → 50% → 100% 的用户
4. 在每个阶段监控 → 关注错误率、性能、用户反馈
5. 清理 → 全量发布后移除标志和死代码路径
规则:
- 每个功能标志都有所有者和过期日期
- 全量发布后 2 周内清理标志
- 不要嵌套功能标志(会产生指数级组合)
- 在 CI 中测试标志的两种状态(打开和关闭)
分阶段发布
发布顺序
1. 部署到预发布环境
└── 在预发布环境运行完整测试套件
└── 对关键流程进行手工冒烟测试
2. 部署到生产环境(功能标志为 OFF)
└── 验证部署成功(健康检查)
└── 检查错误监控(无新错误)
3. 为团队启用(标志为内部用户打开)
└── 团队在生产环境中使用该功能
└── 24 小时监控窗口
4. 金丝雀发布(标志为 5% 的用户打开)
└── 监控错误率、延迟、用户行为
└── 比较指标:金丝雀 vs. 基线
└── 24-48 小时监控窗口
└── 仅在所有阈值通过时才推进(见下表)
5. 逐步增加 (25% -> 50% -> 100%)
└── 每一步都进行相同的监控
└── 能够在任何时候回滚到之前的百分比
6. 全量发布(标志为所有用户打开)
└── 监控 1 周
└── 清理功能标志
发布决策阈值
使用这些阈值来决定在每个阶段是推进、暂停还是回滚:
| 指标 | 推进(绿色) | 暂停并调查(黄色) | 回滚(红色) |
|---|---|---|---|
| 错误率 | 在基线的 10% 以内 | 高于基线 10-100% | 高于基线 2 倍以上 |
| P95 延迟 | 在基线的 20% 以内 | 高于基线 20-50% | 高于基线 50% 以上 |
| 客户端 JS 错误 | 无新错误类型 | 新错误出现在 <0.1% 的会话中 | 新错误出现在 >0.1% 的会话中 |
| 业务指标 | 中性或正面 | 下降 <5%(可能为噪声) | 下降 >5% |
何时回滚
在以下情况下立即回滚:
- 错误率较基线增加超过 2 倍
- P95 延迟增加超过 50%
- 用户报告的问题激增
- 检测到数据完整性问题
- 发现安全漏洞
监控与可观测性
监控哪些内容
应用指标:
├── 错误率(总计和按端点)
├── 响应时间(p50, p95, p99)
├── 请求量
├── 活跃用户
└── 关键业务指标(转化率、参与度)
基础设施指标:
├── CPU 和内存利用率
├── 数据库连接池使用情况
├── 磁盘空间
├── 网络延迟
└── 队列深度(如适用)
客户端指标:
├── 核心 Web 指标(LCP, INP, CLS)
├── JavaScript 错误
├── 从客户端视角的 API 错误率
└── 页面加载时间
错误报告
// 设置带有报告功能的错误边界
class ErrorBoundary extends React.Component {
componentDidCatch(error: Error, info: React.ErrorInfo) {
// 报告给错误跟踪服务
reportError(error, {
componentStack: info.componentStack,
userId: getCurrentUser()?.id,
page: window.location.pathname,
});
}
render() {
if (this.state.hasError) {
return <ErrorFallback onRetry={() => this.setState({ hasError: false })} />;
}
return this.props.children;
}
}
// 服务端错误报告
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
reportError(err, {
method: req.method,
url: req.url,
userId: req.user?.id,
});
// 不要向用户暴露内部信息
res.status(500).json({
error: { code: 'INTERNAL_ERROR', message: 'Something went wrong' },
});
});
发布后验证
发布后第一小时内:
1. 检查健康端点返回 200
2. 检查错误监控仪表板(无新错误类型)
3. 检查延迟仪表板(无回退)
4. 手动测试关键用户流程
5. 确认日志流畅且可读
6. 确认回滚机制有效(如可能则进行预演)
错误预算发布门禁
你的服务的错误预算——允许失败的请求或时间占比——决定了发布是否安全。将其用作客观门禁,而非谈判筹码:
剩余预算 > 20% → 正常发布;密切监控
剩余预算 0–20% → 仅限缓慢发布;不允许高风险变更
预算耗尽 → 冻结特性工作;完全专注于可靠性
预算重置 → 恢复正常节奏;融入使其恢复的修复方案
金丝雀发布期间的高消耗速率(消耗预算速度快于基线速度)是上线发布决策阈值表中的暂停信号——应将其视为与错误率升高同等处理。
回滚策略
每次部署都需要一个在它发生之前的回滚计划:
## [功能/版本] 的回滚计划
### 触发条件
- 错误率 > 基线 2 倍
- P95 延迟 > [X]ms
- 用户报告 [具体问题]
### 回滚步骤
1. 禁用功能标志(如适用)
或
1. 部署上一个版本:`git revert <commit> && git push`
2. 验证回滚:健康检查,错误监控
3. 沟通:通知团队回滚
### 数据库注意事项
- 迁移 [X] 有回滚操作:`npx prisma migrate rollback`
- 新功能插入的数据:[保留 / 清理]
### 回滚时间
- 功能标志:< 1 分钟
- 重新部署上一个版本:< 5 分钟
- 数据库回滚:< 15 分钟
参见
- 关于每个变更在进入此检查清单之前必须通过的项目级“完成定义”,请参见
../../references/definition-of-done.md - 关于安全预发布检查,请参见
../../references/security-checklist.md - 关于性能预发布检查清单,请参见
../../references/performance-checklist.md - 关于发布前的无障碍验证,请参见
../../references/accessibility-checklist.md - 关于告警规则和 SLO 相关阈值,请参见
observability-and-instrumentation
常见合理化说辞
| 合理化说辞 | 现实 |
|---|---|
| “在预发布环境能运行,在生产环境也能运行” | 生产环境有不同的数据、流量模式和边界情况。部署后要进行监控。 |
| “这个功能不需要功能标志” | 每个功能都能从“终止开关”中受益。即使“简单”的变更也可能出问题。 |
| “监控是开销” | 没有监控意味着你是通过用户投诉而不是仪表板来发现问题。 |
| “我们稍后再加监控” | 在上线前添加它。你无法调试你看不到的东西。 |
| “回滚就是承认失败” | 回滚是负责任的工程。发布一个有问题的功能才是失败。 |
| “错误率看起来还好,我们继续发布吧” | 检查消耗速率,而不仅仅是当前错误率。即使单个阈值是绿色的,消耗预算快于基线也是一个暂停信号。 |
危险信号
- 在没有回滚计划的情况下部署
- 生产环境没有监控或错误报告
- 大爆炸式发布(一次性全部推出,没有预发布)
- 没有过期时间或所有者的功能标志
- 没有人在部署后的第一个小时内进行监控
- 生产环境配置凭记忆而非代码
- “现在是周五下午,我们发布吧”
- 错误预算已耗尽,但功能开发仍在继续
验证
部署前:
- 预发布检查清单已完成(所有部分为绿色)
- 功能标志已配置(如适用)
- 回滚计划已记录
- 监控仪表板已设置
- 已通知团队部署相关事宜
部署后:
- 健康检查返回 200
- 错误率正常
- 延迟正常
- 关键用户流程有效
- 日志正常输出
- 回滚已测试或已确认就绪
对于每个已发布的服务:
- 错误预算策略已就位:知道当预算低于 20% 和耗尽时应采取什么行动