蓝绿、滚动与回滚策略
High Contrast
Dark Mode
Light Mode
Sepia
Forest
3 min read690 words

蓝绿、滚动与回滚策略

真正成熟的发布,不是"敢上线",而是"敢回滚"。

三种基本策略对比

策略 适合什么情况 停机时间 回滚速度 复杂度
直接替换 单机、小项目、可接受短暂停机 数秒 慢(重新部署)
蓝绿发布 有双套环境,要求快速切换 零停机 极快(切流量)
滚动发布 多实例服务,要求逐步替换 零停机 中(逐步回滚)

单机蓝绿发布(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新版本(待验证)"]

步骤:

  1. 在端口 3001 启动新版本(不影响 3000 的旧版本):
PORT=3001 APP_VERSION=v2 node server.js &
sleep 5 && curl -sf http://127.0.0.1:3001/health
  1. 通过 Nginx upstream 切换流量:
# /etc/nginx/conf.d/myapp.conf
upstream myapp {
server 127.0.0.1:3001;   # 切到 Green(修改此行)
# server 127.0.0.1:3000; # Blue 保留备用
}
  1. 验证 + 正式切换:
sudo nginx -t && sudo systemctl reload nginx
curl -sf https://yourdomain.com/health
  1. 如需回滚,改回 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_nameusername)。迁移脚本执行了一半被中断,导致数据库处于半迁移状态,新旧代码都无法正常运行。

过程

1. 部署新版本 → 迁移脚本执行中断(数据库连接超时)
2. 健康检查失败 → 自动回滚到旧代码
3. 旧代码访问数据库 → 部分列已被重命名 → 查询报错
4. 结果:新旧版本都不可用,站点完全宕机

教训 & 预防措施:

场景 危险做法 安全做法
字段重命名 直接 ALTER TABLE RENAME 先加新列 → 双写新旧列 → 切换代码 → 删除旧列
删除列 直接 DROP COLUMN 先从代码中移除引用 → 部署 → 再 DROP
加 NOT NULL 列 直接加约束 先加允许 NULL → 填充默认值 → 加约束
迁移超时 无保护直接运行 设置迁移超时,失败立即中止部署

常见误区

误区 正确做法
"蓝绿发布需要双倍服务器" 单机也能做蓝绿——用两个端口运行两个进程,Nginx 切 upstream
"回滚就是重新部署旧版本" 软链接模式下回滚是 ln -sfn + systemctl restart,30 秒完成
"数据库迁移可以随时回滚" 破坏性迁移(删列/改约束)无法简单回滚,需提前设计向后兼容

本节执行清单

下一章数据、存储与备份恢复——发布之外,真正脆弱的是数据。