发布
2026年1月31日大约 7 分钟
发布
在软件开发和运维中,发布(Deployment)是指将新版本的应用部署到生产环境的过程。不同的发布策略有不同的特点,适用于不同的场景。
蓝绿发布(Blue-Green Deployment)
定义
蓝绿发布是一种零停机时间的发布策略,通过维护两个完全相同的生产环境(蓝色和绿色)来实现无缝切换。
工作原理
发布前:
┌─────────┐
│ 负载均衡 │
└────┬────┘
│
├──────────────┐
│ │
┌────▼────┐ ┌────▼────┐
│ 蓝色环境 │ │ 绿色环境 │
│ (生产) │ │ (备用) │
│ v1.0 │ │ v1.0 │
└─────────┘ └─────────┘
发布后:
┌─────────┐
│ 负载均衡 │
└────┬────┘
│
├──────────────┐
│ │
┌────▼────┐ ┌────▼────┐
│ 蓝色环境 │ │ 绿色环境 │
│ (备用) │ │ (生产) │
│ v1.0 │ │ v2.0 │
└─────────┘ └─────────┘发布流程
- 准备阶段:绿色环境部署新版本(v2.0)
- 测试阶段:在绿色环境进行测试验证
- 切换阶段:将流量从蓝色环境切换到绿色环境
- 回滚阶段:如有问题,立即切回蓝色环境
优点
- ✅ 零停机时间:切换瞬间完成,用户无感知
- ✅ 快速回滚:出现问题立即切回旧版本
- ✅ 风险低:新版本完全测试后再切换
- ✅ 简单直接:切换过程简单,易于操作
缺点
- ❌ 资源消耗大:需要维护两套完整环境
- ❌ 成本高:服务器资源翻倍
- ❌ 数据同步:需要处理数据库迁移和同步问题
适用场景
- 对可用性要求极高的系统
- 需要快速回滚的场景
- 资源充足的环境
代码示例
// 蓝绿发布配置示例(Nginx)
// 发布前:所有流量指向蓝色环境
upstream backend {
server blue-server:8080;
}
// 发布后:切换流量到绿色环境
upstream backend {
server green-server:8080;
}
// 或者使用权重逐步切换
upstream backend {
server blue-server:8080 weight=10; # 10%流量
server green-server:8080 weight=90; # 90%流量
}灰度发布(Canary Deployment / 金丝雀发布)
定义
灰度发布是一种渐进式发布策略,先让一小部分用户使用新版本,验证无问题后逐步扩大范围,最终全量发布。
工作原理
阶段1:5% 流量
┌─────────┐
│ 负载均衡 │
└────┬────┘
│
├──────────────┐
│ │
┌────▼────┐ ┌────▼────┐
│ 旧版本 │ │ 新版本 │
│ 95%流量 │ │ 5%流量 │
│ v1.0 │ │ v2.0 │
└─────────┘ └─────────┘
阶段2:50% 流量
┌─────────┐
│ 负载均衡 │
└────┬────┘
│
├──────────────┐
│ │
┌────▼────┐ ┌────▼────┐
│ 旧版本 │ │ 新版本 │
│ 50%流量 │ │ 50%流量 │
│ v1.0 │ │ v2.0 │
└─────────┘ └─────────┘
阶段3:100% 流量
┌─────────┐
│ 负载均衡 │
└────┬────┘
│
│
┌────▼────┐
│ 新版本 │
│ 100%流量│
│ v2.0 │
└─────────┘发布流程
- 灰度阶段1:5% 流量切换到新版本,观察监控指标
- 灰度阶段2:如果无问题,扩大到 20% 流量
- 灰度阶段3:继续扩大到 50% 流量
- 全量发布:100% 流量切换到新版本
- 回滚:如有问题,立即切回旧版本
优点
- ✅ 风险可控:小范围验证,问题影响面小
- ✅ 资源节省:不需要完整的两套环境
- ✅ 数据驱动:根据监控数据决定是否继续
- ✅ 用户友好:大部分用户仍使用稳定版本
缺点
- ❌ 发布周期长:需要多个阶段,耗时较长
- ❌ 复杂度高:需要流量控制和监控系统
- ❌ 数据一致性:需要处理新旧版本的数据兼容
适用场景
- 大型系统的重要更新
- 需要验证新功能的场景
- 对稳定性要求高的系统
代码示例
// 灰度发布 - 基于用户ID的流量分配
@Service
public class GrayReleaseService {
/**
* 判断用户是否在灰度范围
*/
public boolean isInGrayRelease(Long userId, String featureName) {
// 获取灰度配置
GrayReleaseConfig config = grayReleaseConfigRepository
.findByFeatureName(featureName);
if (config == null || !config.isEnabled()) {
return false;
}
// 基于用户ID的哈希值决定是否在灰度范围
int hash = (userId + featureName).hashCode();
int percentage = Math.abs(hash % 100);
return percentage < config.getGrayPercentage();
}
/**
* 获取用户应该使用的版本
*/
public String getUserVersion(Long userId, String featureName) {
if (isInGrayRelease(userId, featureName)) {
return "v2.0"; // 新版本
}
return "v1.0"; // 旧版本
}
}
// 使用示例
@RestController
public class OrderController {
@Autowired
private GrayReleaseService grayReleaseService;
@GetMapping("/orders")
public Result getOrders(@RequestParam Long userId) {
// 根据灰度配置决定使用哪个版本的服务
String version = grayReleaseService.getUserVersion(userId, "order_service");
if ("v2.0".equals(version)) {
return orderServiceV2.getOrders(userId);
} else {
return orderServiceV1.getOrders(userId);
}
}
}Nginx 配置示例
# 灰度发布配置
upstream backend {
# 旧版本服务器
server old-server:8080 weight=95;
# 新版本服务器(灰度)
server new-server:8080 weight=5;
}
# 或者基于请求头进行灰度
map $http_user_id $backend_pool {
default "old";
~*^(1|2|3|4|5)$ "new"; # 用户ID 1-5 使用新版本
}
upstream old {
server old-server:8080;
}
upstream new {
server new-server:8080;
}
server {
location / {
proxy_pass http://$backend_pool;
}
}滚动发布(Rolling Deployment)
定义
滚动发布是一种逐步替换实例的发布策略,逐个或分批更新服务器实例,保持服务始终可用。
工作原理
阶段1:更新实例1
┌─────────┐
│ 负载均衡 │
└────┬────┘
│
├──────┬──────┬──────┐
│ │ │ │
┌────▼──┐ ┌─▼──┐ ┌─▼──┐ ┌─▼──┐
│ 实例1 │ │实例2│ │实例3│ │实例4│
│ v2.0 │ │v1.0│ │v1.0│ │v1.0│
└───────┘ └────┘ └────┘ └────┘
阶段2:更新实例2
┌─────────┐
│ 负载均衡 │
└────┬────┘
│
├──────┬──────┬──────┐
│ │ │ │
┌────▼──┐ ┌─▼──┐ ┌─▼──┐ ┌─▼──┐
│ 实例1 │ │实例2│ │实例3│ │实例4│
│ v2.0 │ │v2.0│ │v1.0│ │v1.0│
└───────┘ └────┘ └────┘ └────┘
最终:所有实例更新完成
┌─────────┐
│ 负载均衡 │
└────┬────┘
│
├──────┬──────┬──────┐
│ │ │ │
┌────▼──┐ ┌─▼──┐ ┌─▼──┐ ┌─▼──┐
│ 实例1 │ │实例2│ │实例3│ │实例4│
│ v2.0 │ │v2.0│ │v2.0│ │v2.0│
└───────┘ └────┘ └────┘ └────┘发布流程
- 分批更新:将实例分成多个批次(如每批 25%)
- 更新批次1:更新第一批实例,等待健康检查通过
- 更新批次2:更新第二批实例,等待健康检查通过
- 继续更新:重复直到所有实例更新完成
- 回滚:如有问题,回滚已更新的实例
优点
- ✅ 资源节省:不需要额外的完整环境
- ✅ 零停机:始终保持服务可用
- ✅ 成本低:相比蓝绿发布成本更低
- ✅ 灵活控制:可以控制更新速度和批次大小
缺点
- ❌ 版本共存:新旧版本会同时运行一段时间
- ❌ 兼容性要求:需要保证新旧版本兼容
- ❌ 回滚复杂:需要逐个回滚实例
- ❌ 发布时间长:需要等待每批实例更新完成
适用场景
- Kubernetes/Docker 容器环境
- 微服务架构
- 资源有限的环境
Kubernetes 滚动更新示例
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 最多可以比期望副本数多1个
maxUnavailable: 1 # 最多可以有1个不可用
template:
spec:
containers:
- name: my-app
image: my-app:v2.0
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5代码示例(健康检查)
// 健康检查接口(用于滚动发布)
@RestController
public class HealthController {
@Autowired
private ApplicationContext applicationContext;
/**
* 就绪检查(Readiness Probe)
* 用于判断服务是否准备好接收流量
*/
@GetMapping("/health/ready")
public ResponseEntity<String> readiness() {
// 检查数据库连接
if (!checkDatabase()) {
return ResponseEntity.status(503).body("Database not ready");
}
// 检查外部服务连接
if (!checkExternalServices()) {
return ResponseEntity.status(503).body("External services not ready");
}
return ResponseEntity.ok("Ready");
}
/**
* 存活检查(Liveness Probe)
* 用于判断服务是否正常运行
*/
@GetMapping("/health/live")
public ResponseEntity<String> liveness() {
return ResponseEntity.ok("Alive");
}
private boolean checkDatabase() {
try {
// 检查数据库连接
return true;
} catch (Exception e) {
return false;
}
}
private boolean checkExternalServices() {
// 检查外部服务连接
return true;
}
}三种发布策略对比
| 对比项 | 蓝绿发布 | 灰度发布 | 滚动发布 |
|---|---|---|---|
| 资源消耗 | 高(需要两套环境) | 中(部分实例) | 低(逐步替换) |
| 发布速度 | 快(瞬间切换) | 慢(分阶段) | 中(分批更新) |
| 回滚速度 | 快(瞬间切回) | 快(立即切回) | 慢(逐个回滚) |
| 风险控制 | 低(完全测试后切换) | 低(小范围验证) | 中(逐步验证) |
| 成本 | 高 | 中 | 低 |
| 复杂度 | 低 | 高 | 中 |
| 适用场景 | 关键系统 | 大型系统 | 容器化环境 |
选择建议
选择蓝绿发布,如果:
- 对可用性要求极高
- 需要快速回滚
- 资源充足
- 系统相对简单
选择灰度发布,如果:
- 大型系统的重要更新
- 需要验证新功能
- 有完善的监控系统
- 需要数据驱动决策
选择滚动发布,如果:
- 使用 Kubernetes/Docker
- 资源有限
- 微服务架构
- 可以接受版本共存
最佳实践
- 健康检查:实现完善的健康检查机制,确保实例真正可用
- 监控告警:实时监控关键指标(错误率、响应时间、QPS等)
- 自动化:使用 CI/CD 工具自动化发布流程
- 回滚预案:提前准备好回滚方案,确保快速回滚
- 数据兼容:保证新旧版本的数据兼容性
- 测试充分:发布前充分测试,减少发布风险
- 分批发布:避免一次性更新所有实例
- 流量控制:使用负载均衡器控制流量分配
总结
三种发布策略各有优缺点,选择哪种策略需要根据:
- 系统特点:系统规模、架构类型
- 业务需求:可用性要求、回滚速度要求
- 资源情况:服务器资源、成本预算
- 技术栈:是否使用容器化、是否有完善的监控
在实际项目中,可以根据不同场景组合使用多种策略,比如:先用灰度发布验证,再用滚动发布全量更新。
