| name | shipping-and-launch |
| description | 准备基础架构生产上线。当准备升级分布式系统、存储引擎或网络组件时使用。当需要上线前检查清单、滚动升级与灰度计划、数据迁移与一致性校验,或需要回滚与降级预案时使用。 |
发布与上线
概述
充满信心地上线。目标不仅仅是把新版本部署上去——而是可靠地部署:协议与磁盘格式兼容性已验证,监控到位,回滚计划就绪,并清楚地理解成功是什么样子。每次上线都应该是可逆的、可观察的和增量的。对分布式系统而言,"可逆"意味着你必须假设新旧版本会长时间混跑,并且回滚时旧版本必须能读懂新版本写下的数据。
何时使用
- 滚动升级分布式系统(数据库、消息队列、协调服务、存储引擎)
- 变更磁盘格式、序列化协议或 RPC 协议
- 执行数据迁移、扩缩容或重均衡(rebalance)
- 执行不可逆操作(数据删除、格式转换、降副本数)
- 任何带有风险的变更(所有变更都有风险)
上线前检查清单
代码质量
兼容性(新旧版本混跑窗口)
数据迁移与一致性
容量与水位线
不可逆操作门禁
基础设施
文档
功能开关与灰度策略
在功能开关后面发布高风险行为,将二进制部署与行为启用解耦。对基础架构而言,开关通常控制:新格式写入、新代码路径、双写比对:
if cfg.EnableNewRecordFormat {
return writeRecordV2(buf, record)
}
return writeRecordV1(buf, record)
功能开关生命周期:
1. 部署 开关关闭 → 新二进制在运行,行为与旧版本一致
2. 启用 在测试集群 → 用生产流量的回放/影子流量验证
3. 灰度启用 → 单节点 → 单机架 → 单集群 → 全量
4. 每个阶段监控 → 观察错误率、延迟、副本滞后、校验和不匹配数
5. 清理 → 全量稳定后移除开关和旧代码路径
规则:
- 每个开关有一个所有者和到期日期
- 全量启用并稳定 2 周后清理开关和死代码路径
- 格式写入类开关默认关闭,且开启后必须有"关闭开关即恢复旧格式写入"的验证路径
- 在 CI 中测试两种开关状态(开和关)
- 涉及磁盘格式的开关,开启前必须确认集群不再计划回滚到旧二进制
分阶段上线
上线序列
1. 在测试/预发集群验证
└── 用生产数据副本或回放流量跑完整测试套件
└── 注入故障演练:升级中杀节点、断网、塞满磁盘
2. 单节点升级(canary)
└── 升级集群中一个非关键节点
└── 验证:正常加入集群、副本同步追平、读写正常
└── 至少 24 小时观察窗口
3. 单机架升级
└── 升级一个故障域内的所有节点
└── 验证:机架级故障域隔离仍有效,副本分布不越界
└── 监控副本滞后、重建速率、IO 错误
4. 单集群升级
└── 升级一个完整集群(跨机架滚动进行)
└── 每一步等待副本追平和健康检查通过
└── 24-48 小时监控窗口
5. 全量推广(剩余集群按批次)
└── 每批之间留出观察窗口
└── 任何时候能停止推广并回滚已升级节点
6. 启用新行为(如格式开关)
└── 仅在所有节点升级完成且不再计划回滚之后
└── 按"单节点 → 单机架 → 单集群 → 全量"重新灰度
扩容与重均衡上线
1. 新节点上线为空节点,先不承接流量
2. 开启重均衡,限速到不影响业务 P99(如限制搬迁带宽 ≤ 磁盘能力的 20%)
3. 监控:搬迁速率、源/目标节点 IO 延迟、副本可用性、业务延迟
4. 触发任一红线立即暂停重均衡(pause),而不是等它自己跑完
5. 搬迁完成后做副本一致性校验,再开放新节点承接全量流量
上线决策阈值
使用这些阈值来决定在每个阶段是推进、暂停还是回滚:
| 指标 | 推进(绿色) | 暂停并调查(黄色) | 回滚/停止(红色) |
|---|
| RPC 错误率 | 在基准的 10% 以内 | 高于基准 10-100% | > 基准 2 倍 |
| P99 延迟 | 在基准的 20% 以内 | 高于基准 20-50% | > 高于基准 50% |
| 副本滞后(replication lag) | 追平且稳定 | 持续增长但可恢复 | 持续增长且预计写满磁盘 |
| 校验和/一致性不匹配 | 0 | 个别且可归因于已知问题 | 批量出现或无法归因 |
| 磁盘水位 | <70% | 70-85% | >85% 或单盘写满 |
| 节点宕机/重启 | 无异常 | 单点偶发重启 | 同一版本节点批量崩溃 |
何时回滚或停止
在以下情况下立即停止推进并回滚:
- 同一新版本的节点批量崩溃或无法加入集群
- 检测到数据损坏或校验和批量不匹配
- 副本滞后持续增长,存在数据丢失风险
- P99 延迟劣化超过 50% 且影响依赖方
- 磁盘水位越过红线,重建无法完成
监控与可观测性
监控什么
服务指标:
├── RPC 错误率(总计和按方法)
├── 响应时间(p50、p99、p999)
├── 请求量和吞吐
├── 慢请求/超时计数
└── 队列深度(写队列、复制队列、compaction 队列)
分布式系统指标:
├── 副本滞后与同步状态(replication lag、under-replicated 数量)
├── Leader/选举稳定性(选举频率、lease 续约失败)
├── 一致性指标(校验和不匹配数、对账差异)
├── 重均衡/搬迁速率与剩余量
└── 成员变更事件(节点上下线、扩缩容)
主机与存储指标:
├── 磁盘容量水位、inode、IO 延迟与 util
├── 慢盘/坏盘检测(IO error、retry 计数)
├── CPU、内存、页缓存命中
├── 网络吞吐、重传、分区检测
└── 文件描述符、连接数
错误报告与告警
if err != nil {
metrics.IncWriteErrors(cfg.ClusterID, cfg.NodeID)
logger.Error("write failed",
"cluster", cfg.ClusterID,
"node", cfg.NodeID,
"partition", partitionID,
"error", err,
"checksum_mismatch", isChecksumErr(err),
)
if isChecksumErr(err) {
alerting.PageOncall("checksum mismatch", partitionID)
}
}
告警分级原则:
- 数据正确性(校验和不匹配、副本丢失)→ 立即 pager
- 可用性(节点宕机、副本不足)→ 分钟级告警
- 性能退化(延迟、水位)→ 阈值 + 趋势告警
上线后验证
在升级每个阶段后的第一个小时内:
1. 检查节点健康状态与集群成员关系正常
2. 检查错误监控仪表盘(无新错误类型)
3. 检查延迟与副本滞后仪表盘(无回归)
4. 抽查读写路径:写入 → 读取 → 校验和比对
5. 验证日志在流动且可读
6. 确认回滚机制有效(本阶段至少演练一次单节点回退)
回滚与降级策略
每次变更都需要在发生之前有一个回滚计划。基础架构的回滚有一个 Web 发布没有的核心约束:回滚后的旧二进制必须能读懂升级期间写入的数据。
## [变更/升级]的回滚计划
### 触发条件
- 校验和不匹配批量出现
- 副本滞后持续增长超过 [X] 分钟
- P99 延迟 > [X]ms
- 节点批量崩溃且共同点是新版本
### 数据兼容性确认(回滚前置条件)
- 升级期间是否写入了新格式数据?[是/否]
- 若否:可直接回退二进制
- 若是:旧版本是否能读?[能 → 回退 / 不能 → 禁止回退,走修复向前 roll-forward]
- 格式开关是否已开启?[已开启 → 先关闭开关,确认全部恢复旧格式写入,再评估回退]
### 回滚步骤
1. 停止推进:暂停滚动升级/重均衡(pause,不是继续)
2. 按逆序回退节点:逐台回退,每台验证重新加入集群且副本追平
3. 验证:健康检查、读写抽查、校验和比对
4. 沟通:通知团队和依赖方
### 降级预案(回滚不可行时)
- 关闭新功能开关,退回旧行为
- 读路径降级:从副本/备集群读
- 写路径降级:限流、排队或切到备用写入路径
- 数据修复:从备份/快照恢复受影响分区
### 回滚时间
- 停止推进/暂停重均衡:< 1 分钟
- 关闭功能开关:< 5 分钟
- 单节点回退二进制:< 15 分钟
- 从快照恢复单分区:< [X] 小时(实测,非估计)
参见
- 项目范围的完成定义,每个变更在此检查清单之前都需要清除它,见
references/definition-of-done.md
- 性能与容量上线前检查清单,见
references/performance-checklist.md
- 上线前的可观测性验证,见
references/observability-checklist.md
常见合理化借口
| 合理化借口 | 现实 |
|---|
| "测试集群升级没问题,生产也一样" | 生产有不同的数据量、数据倾斜和故障模式。测试集群不会替你发现混跑窗口里的兼容性问题。 |
| "滚动升级不需要等副本追平,直接下一台" | 不等追平就是在叠加故障域。连续升级两台副本未同步的节点,等于自己制造数据丢失。 |
| "新版本会写新格式,但我们应该不用回滚" | "应该不用"不是回滚计划。一旦需要回滚而旧版本读不了新数据,你就被困在新版本上了。 |
| "重均衡全速跑,跑完就完事了" | 不限速的搬迁会打爆磁盘 IO 和网络,把正常的延迟尖刺变成线上事故。限速是默认项,不是可选项。 |
| "删数据前不用再确认,脚本是对的" | 不可逆操作没有"脚本是对的"这回事。dry-run、审批、快照,一个都不能少。 |
| "磁盘还有 20%,够用" | 重建一个故障节点需要整个节点容量的冗余空间。水位线要按故障场景算,不是按当前用量算。 |
| "回滚就是承认失败" | 回滚是负责任的工程。带着校验和不匹配硬扛才是失败。 |
红旗警告
- 没有验证新旧版本混跑兼容性就开始滚动升级
- 格式转换或数据删除没有显式审批就执行
- 没有备份或快照就做不可逆操作,或备份从未验证过可恢复
- 重均衡/迁移不限速,或跑在业务高峰期
- 上线前不看容量水位线,升级过程中磁盘写满
- 回滚计划没有回答"旧版本能读懂新数据吗"
- 大爆炸式全集群同时升级,没有单节点 canary
- "星期五下午了,我们把这批集群升完吧"
验证
上线之前:
上线之后(每个灰度阶段):