本文目录导读:

“零停机发布”(Zero Downtime Deployment, ZDD)是指在更新应用或服务时,用户在整个过程中完全无感知,不会出现服务不可用或请求失败的情况。
这是一个系统工程,没有单一的“银弹”,通常需要结合多种策略,以下是实现零停机发布的核心步骤、常见模式以及技术要点。
核心原则:流量控制和资源隔离
零停机的本质是让新旧两套系统(旧版本和新版本)同时在线一小段时间,并平滑地将流量从旧系统切换到新系统。
架构层面的前提条件
在下发代码之前,你的架构必须做好准备:
- 负载均衡器(Load Balancer):这是最关键的前置设备,它负责统一入口,并将流量分发到后端的多台服务器上。
- 无状态化(Stateless):你的应用实例本身不应存储任何用户会话(Session)或本地缓存数据,所有状态应集中存放在外部数据库、Redis或对象存储中。
- 健康检查(Health Check):负载均衡器必须配置健康检查API(
/health),只有当新版本实例健康检查通过后,它才被允许接入流量。 - 数据库向后兼容(Backward Compatible DB Schema):这是最容易忽略也最容易导致事故的点。 新代码必须能读写旧数据库Schema,旧代码也必须能在旧数据库Schema上运行(因为切换的瞬间可能有共存)。
四种主流的零停机发布模式
从简单到复杂,可以选择以下模式:
模式1:蓝绿部署(Blue-Green Deployment)—— 最简单、最安全
- 原理:
- 准备两个完全相同的生产环境:蓝环境(当前运行,V1)和绿环境(准备部署,V2)。
- 先在绿环境上部署V2,并进行全面验证(功能、性能测试)。
- 验证无误后,在负载均衡器上一键切换所有流量入口,从蓝环境指向绿环境。
- 切换完成后,蓝环境保留作为回滚备用。
- 优点:切换快,回滚极快(指回蓝环境瞬间恢复)。
- 缺点:需要双倍硬件资源成本。
模式2:滚动发布(Rolling Update)—— 最常用、成本适中
- 原理:
- 逐步、分批替换后端集群中的实例。
- 有10台服务器,先关闭1台老版本,启动1台新版本,确认正常后,再替换第2台,以此类推。
- 优点:资源成本低,影响范围小(每次只动一小部分)。
- 缺点:发布周期长(需要等待所有批次替换完成);回滚麻烦(需要反向滚动)。
模式3:灰度发布(Canary Release)—— 最精细、适合测试
- 原理:
- 在滚动更新的基础上,引入流量权重控制。
- 先只更新1-2台实例(金丝雀),只让1% 的流量进入新版本(通常是内部用户或测试引擎)。
- 监控这1%流量的错误率、延迟、业务指标,如果一切正常,逐步将流量比例提高到10%、50%、100%。
- 优点:风险最低,能在小范围真实流量中发现潜在问题。
- 缺点:对监控和流量控制能力要求高。
模式4:红黑部署(Red-Black Deployment)—— 类似蓝绿,但更自动化
- 原理:在容器编排平台(如Kubernetes)中,通过Service和Deployment配合实现,本质是蓝绿,但通过云原生技术自动化完成。
数据库迁移(Database Migrations)的零停机
这是最大的挑战。 对表结构的修改(如新增列、修改列类型、建索引)很容易导致新旧代码冲突。
策略:分步骤、无损(Expand-Migrate-Contract Pattern)
假设要重命名列 status 为 state:
- 步骤1:Expand(扩展)
- 部署新代码,同时写入新旧两个字段
status和state,数据库新增state列(允许空)。 - 旧代码此时仍然读/写
status。
- 部署新代码,同时写入新旧两个字段
- 步骤2:Migrate(迁移)
- 运行后台脚本,将
status的数据复制到state。 - 部署新代码,使其只读
status并写入state(双写,但读的切换完成)。
- 运行后台脚本,将
- 步骤3:Contract(收缩)
- 确保所有代码都只读/写
state。 - 通过数据库迁移删除
status列。
- 确保所有代码都只读/写
原则:每一个步骤的代码变更都是向前兼容的。
实践中的关键工具
- 容器编排:Kubernetes + Deployment(原生支持滚动更新,设置
maxSurge和maxUnavailable)。 - 服务网格:Istio / Linkerd,可以在更细粒度上控制流量权重(如按Header、Cookie、地域灰度)。
- 功能开关:LaunchDarkly / Unleash,允许在不发布代码的情况下,远程打开/关闭某个新功能(暗部署 Dark Launch)。
- 监控与可观测性:你必须能实时看到发布过程中 P99 延迟、错误率(Error Rate) 和 吞吐量 的变化,工具如 Prometheus + Grafana + Jaeger。
一份简化的零停机发布清单
-
准备:
- [ ] 代码无状态化。
- [ ] 数据库Schema兼容性检查。
- [ ] 配置中心提前设置好新版本参数。
- [ ] 测试环境先跑一轮自动化测试。
-
执行(以滚动更新为例):
- [ ] 通知负载均衡器,将新启动的实例标记为
ready后开始接收流量。 - [ ] 逐一或分批停止旧版本实例。
- [ ] 每次替换后,自动运行健康检查。
- [ ] 监控面板观察5分钟(黄金指标)。
- [ ] 通知负载均衡器,将新启动的实例标记为
-
异常处理:
- [ ] 如错误率上升,立即停止发布(Kubernetes 自动会做)。
- [ ] 触发回滚:在Kubernetes中执行
kubectl rollout undo deployment my-app。 - [ ] 回滚后检查数据库状态是否已回退(通常不需要回退数据库Schema,只需保证代码兼容)。
- 简单场景(单体、实例少):直接用 蓝绿部署。
- 微服务场景(实例多、团队多):推荐 Kubernetes滚动更新 + 灰度(Canary)。
- 最关键的一步:管理好数据库变更,确保任何时刻新旧代码都能共存读/写。
- 没有100%的零停机:总有极低概率(如硬件故障),但遵循上述模式,可以将发布导致的停机时间缩短到数据库迁移操作的那几毫秒(甚至为0)。