蓝绿、滚动与回滚策略
真正成熟的发布,不是"敢上线",而是"敢回滚"。
三种基本策略对比
| 策略 | 适合什么情况 | 停机时间 | 回滚速度 | 复杂度 |
|---|---|---|---|---|
| 直接替换 | 单机、小项目、可接受短暂停机 | 数秒 | 慢(重新部署) | 低 |
| 蓝绿发布 | 有双套环境,要求快速切换 | 零停机 | 极快(切流量) | 中 |
| 滚动发布 | 多实例服务,要求逐步替换 | 零停机 | 中(逐步回滚) | 高 |
单机蓝绿发布(Nginx upstream 切换)
graph LR
U[用户流量] --> N[Nginx]
N --> B["Blue: 127.0.0.1:3000\n旧版本(当前生产)"]
N -.切换.-> G["Green: 127.0.0.1:3001\n新版本(待验证)"]
步骤:
- 在端口
3001启动新版本(不影响3000的旧版本):
PORT=3001 APP_VERSION=v2 node server.js &
sleep 5 && curl -sf http://127.0.0.1:3001/health
- 通过 Nginx upstream 切换流量:
# /etc/nginx/conf.d/myapp.conf
upstream myapp {
server 127.0.0.1:3001; # 切到 Green(修改此行)
# server 127.0.0.1:3000; # Blue 保留备用
}
- 验证 + 正式切换:
sudo nginx -t && sudo systemctl reload nginx
curl -sf https://yourdomain.com/health
- 如需回滚,改回 upstream 指向
3000再 reload:
# 60 秒内完成回滚
sed -i 's/3001/3000/' /etc/nginx/conf.d/myapp.conf
sudo nginx -t && sudo systemctl reload nginx
基于软链接的版本管理(单机推荐模式)
/opt/myapp/
├── releases/
│ ├── 20260321-1000/ # 旧版本
│ ├── 20260322-1400/ # 当前版本(软链接目标)
│ └── 20260322-1600/ # 新版本(部署中)
├── current -> releases/20260322-1400/ # 软链接
└── backup-20260322/ # 最近备份
版本管理脚本:
#!/usr/bin/env bash
# rollback.sh — 回滚到上一个 release
set -euo pipefail
APP_DIR=/opt/myapp
# 找出上一个 release(按时间排序,第 2 个)
PREV=$(ls -td $APP_DIR/releases/*/ | sed -n '2p' | sed 's|/$||')
if [[ -z "$PREV" ]]; then
echo "没有可用的旧版本,无法回滚" && exit 1
fi
echo "回滚到: $PREV"
ln -sfn "$PREV" "$APP_DIR/current"
sudo systemctl restart myapp
sleep 3
curl -sf http://127.0.0.1:3000/health && echo "回滚成功" || echo "回滚后健康检查失败,手动介入!"
真实案例:数据库迁移导致的部署失败
背景:某团队部署 Node.js 应用时,新版本引入了一个字段重命名迁移(user_name → username)。迁移脚本执行了一半被中断,导致数据库处于半迁移状态,新旧代码都无法正常运行。
过程:
1. 部署新版本 → 迁移脚本执行中断(数据库连接超时)
2. 健康检查失败 → 自动回滚到旧代码
3. 旧代码访问数据库 → 部分列已被重命名 → 查询报错
4. 结果:新旧版本都不可用,站点完全宕机
教训 & 预防措施:
| 场景 | 危险做法 | 安全做法 |
|---|---|---|
| 字段重命名 | 直接 ALTER TABLE RENAME | 先加新列 → 双写新旧列 → 切换代码 → 删除旧列 |
| 删除列 | 直接 DROP COLUMN | 先从代码中移除引用 → 部署 → 再 DROP |
| 加 NOT NULL 列 | 直接加约束 | 先加允许 NULL → 填充默认值 → 加约束 |
| 迁移超时 | 无保护直接运行 | 设置迁移超时,失败立即中止部署 |
常见误区
| 误区 | 正确做法 |
|---|---|
| "蓝绿发布需要双倍服务器" | 单机也能做蓝绿——用两个端口运行两个进程,Nginx 切 upstream |
| "回滚就是重新部署旧版本" | 软链接模式下回滚是 ln -sfn + systemctl restart,30 秒完成 |
| "数据库迁移可以随时回滚" | 破坏性迁移(删列/改约束)无法简单回滚,需提前设计向后兼容 |
本节执行清单
- [ ] 为当前项目定义具体回滚步骤(脚本化)
- [ ] 确认 releases 目录保留最近 3 个版本
- [ ] 给每次发布记录版本号和时间戳
- [ ] 测试回滚脚本(在测试环境验证可以在 60 秒内完成)
- [ ] 如有数据库迁移,评估是否可逆
下一章:数据、存储与备份恢复——发布之外,真正脆弱的是数据。