3、蓝绿部署实战:蓝绿部署架构、DNS切换与负载均衡器配置、数据库兼容性问题

3.1 蓝绿部署的核心思想

蓝绿部署,说白了就是准备两套完全一样的环境。

一套叫「蓝」,是当前在线的生产环境。

另一套叫「绿」,是你要发布的新版本环境。

两套环境同时运行,但只有一套对外提供服务。

我刚开始接触这个模式时,觉得有点浪费资源。但经历过一次线上事故后,我彻底改观了。那次回滚花了40分钟,用户流失惨重。如果当时用了蓝绿部署,切换就是几秒钟的事。

蓝绿部署的核心优势就两个:

  • 快速切换:发现问题,一秒切回旧版本
  • 零 downtime:用户几乎感知不到发布过程

关键点:蓝绿部署不是「逐步切换」,而是「瞬间切换」。这是它和金丝雀发布的本质区别。

3.2 蓝绿部署架构设计

一个标准的蓝绿部署架构,通常包含这几层:

层级 组件 说明
流量入口 DNS / CDN 负责域名解析,指向当前活跃环境
负载均衡 Nginx / HAProxy / ALB 分发流量到后端服务集群
应用层 蓝集群 / 绿集群 两套完全隔离的应用实例
数据层 数据库 / 缓存 需要处理兼容性问题

我个人习惯把蓝绿环境部署在不同的物理机群或 Kubernetes 命名空间里。这样能真正做到「物理隔离」,避免互相影响。

举个例子,我在阿里云上做过一个方案:

# 蓝环境(当前在线)
blue-cluster:
  - 10.0.1.10:8080 (app-1)
  - 10.0.1.11:8080 (app-2)
  - 10.0.1.12:8080 (app-3)

# 绿环境(新版本)
green-cluster:
  - 10.0.2.10:8080 (app-1)
  - 10.0.2.11:8080 (app-2)
  - 10.0.2.12:8080 (app-3)

两套环境独立部署,互不干扰。发布时,先在绿环境部署新版本,验证通过后,把流量切过去。

3.3 DNS切换:最粗暴也最有效

DNS切换是蓝绿部署里最简单的方式。你只需要修改域名解析,把流量指向新环境。

但这里有个坑——DNS缓存

我曾经遇到过一个问题:DNS切换后,过了半小时还有用户访问旧环境。排查发现,运营商 DNS 缓存 TTL 设成了 1800 秒。

避坑指南:DNS切换前,一定要把 TTL 值调低。我一般提前 24 小时把 TTL 从 600 秒降到 60 秒。等切换完成稳定后,再调回正常值。

DNS切换的步骤大致如下:

  1. 提前降低 TTL(比如 60 秒)
  2. 在绿环境部署新版本,完成验证
  3. 修改 DNS 记录,指向绿环境 IP
  4. 等待 DNS 生效(通常几分钟)
  5. 监控流量和错误率
  6. 确认稳定后,保留蓝环境作为回滚备用

说白了,DNS切换适合「不要求秒级切换」的场景。如果你需要更快的切换速度,那就得上负载均衡器了。

3.4 负载均衡器配置实战

用负载均衡器做蓝绿切换,比 DNS 快得多。你只需要修改 upstream 配置,把流量从蓝集群切到绿集群。

我拿 Nginx 举个例子:

# 定义两个 upstream
upstream blue-cluster {
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

upstream green-cluster {
    server 10.0.2.10:8080;
    server 10.0.2.11:8080;
    server 10.0.2.12:8080;
}

# 当前指向蓝环境
server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://blue-cluster;
    }
}

切换时,只需要把 proxy_passblue-cluster 改成 green-cluster,然后 reload Nginx:

nginx -s reload

整个过程不到 1 秒。用户完全无感知。

小技巧:我习惯在 Nginx 里加一个健康检查。如果绿环境有问题,Nginx 会自动切回蓝环境。这样即使人不在电脑前,也能自动回滚。

用 HAProxy 也是类似的思路:

backend app-backend
    option httpchk GET /health
    server blue-1 10.0.1.10:8080 check weight 100
    server blue-2 10.0.1.11:8080 check weight 100
    server green-1 10.0.2.10:8080 check weight 0
    server green-2 10.0.2.11:8080 check weight 0

切换时,把蓝环境的 weight 改成 0,绿环境的 weight 改成 100。然后 reload 配置。

你想想看,这种方式比 DNS 切换快多了吧?

3.5 数据库兼容性问题:最容易被忽视的坑

嗯,这里要注意。蓝绿部署最大的坑,不在应用层,而在数据库层。

为什么?因为数据库是「有状态」的。两套应用可以同时跑,但数据库不能同时跑两个版本。

我遇到过最典型的问题是这样的:

  • 新版本改了数据库表结构(加了字段)
  • 蓝环境还在用旧版本,不识别新字段
  • 绿环境写入新字段后,蓝环境读取报错

说白了,数据库的兼容性问题,核心就一句话:新老版本必须能同时读写同一份数据

怎么解决?我总结了几个实战经验:

方案一:向后兼容的数据库变更

所有数据库变更,必须做到「向前兼容」。什么意思?

  • 只加字段,不改字段
  • 只加表,不改表
  • 新字段要有默认值
  • 不要删除旧字段

举个例子:

-- 错误做法:直接删除旧字段
ALTER TABLE users DROP COLUMN old_field;

-- 正确做法:先加新字段,等所有版本都迁移后再删除
ALTER TABLE users ADD COLUMN new_field VARCHAR(255) DEFAULT '';

方案二:读写分离 + 数据同步

如果变更实在太大,可以考虑读写分离:

  • 蓝环境读写主库
  • 绿环境读写从库(或影子库)
  • 通过数据同步工具(如 Canal、Debezium)把数据从主库同步到从库

这个方案比较复杂,我一般只在「大版本升级」时才用。

方案三:双写 + 灰度切换

新老版本同时写入数据库,但只从一个版本读取。等数据一致后,再切换读取源。

重要提醒:数据库兼容性问题,一定要在「发布前」就规划好。我见过太多团队,应用层切过去了,数据库却炸了。结果回滚都来不及。

3.6 蓝绿部署的完整流程

最后,我总结一下蓝绿部署的完整流程:

  1. 准备阶段:搭建蓝绿两套环境,确保配置一致
  2. 部署阶段:在绿环境部署新版本,运行验证测试
  3. 切换阶段:通过 DNS 或负载均衡器,把流量切到绿环境
  4. 观察阶段:监控错误率、延迟、数据库状态,持续 15-30 分钟
  5. 清理阶段:确认稳定后,保留蓝环境作为回滚备用

如果发现问题,直接切回蓝环境。整个过程不超过 10 秒。

我个人觉得,蓝绿部署是「性价比最高」的发布策略。它不像金丝雀发布那么复杂,也不像滚动发布那么慢。只要处理好数据库兼容性问题,几乎适用于所有场景。

好了,这一章就到这里。下一章我们聊聊「金丝雀发布」的实战细节,那个更有意思。