← 返回展示台

阿里云部署与不停机升级方案

前提:上线后不允许停机维护。本文给出可落地的部署拓扑、灰度流程与回滚预案。


一、环境划分

环境用途规格建议数据
dev开发自测2C4G × 1造数据
test集成测试4C8G × 2脱敏数据
staging预发(与生产同规格)8C16G × 2生产脱敏快照
prod生产8C32G × 3(最小)真实

staging 必须与生产同规格,否则压测与容量评估全部失效。
这是最容易被省钱砍掉、然后在上线当天付出代价的一项。


二、生产最小可用拓扑(一期)

                    ┌──────────────┐
                    │  SLB / ALB   │  ← 公网入口,多可用区
                    └──────┬───────┘
                           │
              ┌────────────┴────────────┐
              │        WAF 3.0          │
              └────────────┬────────────┘
                           │
         ┌─────────────────┴──────────────────┐
         │      ACK 集群(3 节点,多可用区)     │
         │  ┌──────────────────────────────┐  │
         │  │ gateway (2 副本)              │  │
         │  │  ├─ 鉴权 / 限流 / 租户识别     │  │
         │  │  └─ 灰度路由                  │  │
         │  ├──────────────────────────────┤  │
         │  │ business-svc (3 副本)         │  │  ← 房源/合同/计费/工单
         │  │ integration-svc (2 副本)      │  │  ← 支付/OTA/签章/AR 集成
         │  │ agent-svc (2 副本)            │  │  ← Agent 能力
         │  │ job-worker (2 副本)           │  │  ← 账单生成/对账/outbox 投递
         │  └──────────────────────────────┘  │
         └─────────────────┬──────────────────┘
                           │
    ┌──────────┬───────────┼────────────┬──────────────┐
    │          │           │            │              │
┌───┴────┐ ┌───┴────┐ ┌────┴─────┐ ┌────┴────┐ ┌──────┴──────┐
│RDS PG  │ │Redis   │ │RocketMQ  │ │  OSS    │ │Elasticsearch│
│主+2只读│ │集群版  │ │专业版    │ │+ CDN    │ │ 3 节点      │
│多可用区│ │双副本  │ │          │ │         │ │             │
└────────┘ └────────┘ └──────────┘ └─────────┘ └─────────────┘

旁路(二期):ClickHouse(IoT/报表)

规格建议(一期,100 万房源以内)

组件规格说明
ACK 节点8C32G × 3多可用区部署,单节点故障不影响
RDS PostgreSQL16C64G,ESSD PL1 1TB,多可用区主库
RDS 只读实例8C32G × 2①报表 ②C 端查询
Redis 集群版8G × 3 分片,双副本会话/缓存/锁
RocketMQ专业版,4C8G事务消息必需
OSS标准存储 + CDN图片/AR 资源
SLB/ALB性能保障型按流量选

⚠️ RDS 规格宁大勿小:数据库升级需要停机或切换,
而应用层扩缩容是滚动无感的。把资源余量留在数据库上。


三、不停机升级的标准流程

3.1 应用发布(无状态服务)

① 代码合并 → CI 构建镜像 → 推送 ACR
② staging 部署 → 自动化回归 + 冒烟
③ 生产灰度:
   ├─ 步骤1:部署 1 个新版本 Pod(占 1/4 流量)
   ├─ 步骤2:观察 30 分钟(错误率/延迟/业务指标)
   ├─ 步骤3:扩到 50% → 观察
   ├─ 步骤4:全量
   └─ 任一步异常 → 立即缩容新版本,流量回旧版本(秒级)
④ 旧版本 Pod 保留至少 30 分钟再下线(保证长连接平滑迁移)

技术前提(缺一不可):

前提不满足的后果
应用无状态(会话在 Redis)无法多副本,无法滚动
优雅关闭(preStop + SIGTERM 处理)请求被硬断,用户看到错误
健康检查(liveness + readiness 分离)新 Pod 未就绪就接流量
数据库变更向后兼容新旧版本数据冲突
接口幂等重试导致重复扣款

3.2 数据库变更(最关键,最容易出事)

必须遵守 Expanding / Contracting 五步法。 以「账单增加 refunding 状态」为例:

阶段操作可回滚说明
① Expand放宽 CHECK 约束,允许新值✅ 随时纯 DDL,秒级,不锁表
② Deploy A新代码可写新值,旧代码读到按 pending 处理✅ 回滚代码即可灰度期间两版共存
③ Migrate后台分批把存量数据规范化✅ 幂等可重跑每批 5000 行,避免长事务
④ Deploy B移除兼容旧状态的代码✅此时全量新代码
⑤ Contract收紧约束、删废弃列❌ 不可回滚必须等所有旧实例下线

红线清单(CI 中应自动拦截):

操作判定替代方案
ADD COLUMN ... NOT NULL 无默认值🔴 禁止先 nullable + 回填 + 加约束
RENAME COLUMN/TABLE🔴 禁止新增 + 双写 + 迁移 + 删除
ALTER COLUMN TYPE🔴 禁止(大表)新增列 + 转换 + 切换
CREATE INDEX(不带 CONCURRENTLY)🔴 禁止CREATE INDEX CONCURRENTLY
DROP COLUMN 后 2 个版本内🟠 警告延后删除
全表 UPDATE🔴 禁止分批(LIMIT + 循环)
VACUUM FULL🔴 生产禁止pg_repack
LOCK TABLE🔴 禁止调整业务逻辑

配套实现:DDL/09-分布式一致性.sql 中的 schema_migration 表带
is_destructive / is_online_safe 字段,应在 CI 中强制校验:
破坏性变更必须标记并走审批。

3.3 账单批生成这类「重任务」的不停机做法

每月 1 号生成数百万张账单,这是最容易造成停机的操作。

❌ 错误做法:一个大事务跑完,锁表数分钟。

✅ 正确做法:

① 按月/租户切分任务,投递到 MQ(每租户一个消息)
② worker 并发消费,每个任务独立事务(只处理一个租户的账单)
③ 幂等:bill 表的 idempotency_key 保证重复消费不会多生成(已验证)
④ 进度可查:任务表记录每个租户的处理状态
⑤ 失败可重试:单租户失败不影响其他租户
⑥ 限流:控制并发数,避免打满数据库

关键点:账单生成必须是「幂等 + 可断点续跑」的。

月中发现问题可以随时重跑,不会重复生成。


四、回滚预案

场景回滚手段目标时间
应用异常缩容新版本 Pod / 切回旧镜像< 1 分钟
新功能有问题特性开关关闭(不发版)< 10 秒
数据库变更引发问题执行反向迁移脚本< 5 分钟
数据写错按业务单号精确修复(不做全库回滚)视范围
主库故障RDS 自动主备切换30~60 秒(有闪断)
整个可用区故障多可用区自动切换1~3 分钟

必须提前准备的资产:

  1. 每个数据库变更都配反向迁移脚本(写在同一个 PR 里)
  2. 关键业务的数据修复脚本模板(按单号修复,非全表)
  3. 一份回滚检查清单,演练过至少一次

五、监控与告警(上线前必须有)

层次指标告警阈值工具
数据库连接数使用率> 80%RDS 监控
数据库主备延迟> 10 秒RDS 监控
数据库慢查询数(>1s)> 10 条/分钟RDS 慢日志 + ARMS
数据库死锁与长事务长事务 > 30 秒自定义告警
应用接口 P99 延迟> 500msARMS
应用错误率> 1%ARMS
业务收租成功率< 99%自定义埋点
业务支付回调失败数> 0对账任务
业务outbox 积压量> 1000定时查询
集成第三方接口失败率> 5%integration_call_log
对账对账差异数> 0对账任务

只监控技术指标是不够的。 上面标粗的三项是业务指标:
收租成功率掉点、outbox 积压、对账差异 —— 这三项能最早发现业务级故障。


六、上线前检查清单

基础设施

应用

数据

业务

连接池大小计算(重要)

应用连接数 = Pod数 × (每Pod最大连接数)
必须满足:应用连接总数 < RDS max_connections × 0.8

例:6 个 Pod × 每 Pod 20 连接 = 120 连接
    RDS 16C64G 的 max_connections 约 4000,安全

⚠️ 但连接数不是越多越好。PostgreSQL 的经验值是
活跃连接数 ≈ CPU 核数 × 2~4,超过后性能反而下降。
单 Pod 的连接池建议 10~20,靠多 Pod 横向扩展。


七、二期/三期演进路径

触发条件演进动作
只读副本 CPU > 70%增加只读副本
主库 CPU > 50% 持续读写分离细化(C 端走副本)
报表拖慢主库引入 ClickHouse / AnalyticDB
单库 > 2TB按 tenant_id 分库(ShardingSphere)
单个大租户资源占用过高该租户迁独立库(isolation_mode 已预留)
商城/直播上线独立集群 + 独立库,与主业务物理隔离

分库的技术前提(现在就要准备):

  1. 所有表必须有 tenant_id(已满足)
  2. 所有查询必须带 tenant_id(RLS 已强制)
  3. 避免跨租户 JOIN(当前设计已避免)
  4. 分布式 ID 生成(当前用 bigint identity,分库时需改雪花 ID)
  5. 分布式事务方案确定(建议:避免跨库事务,用 Saga/最终一致)

第 4 点是个隐患:当前主键用 GENERATED ALWAYS AS IDENTITY,
分库后会冲突。建议一期就引入雪花 ID 或号段分配,
避免分库时大规模改主键。这是我在本设计中要提醒的改进项。


配套:../分布式架构/01-阿里云分布式架构.md

目录

  1. 一、环境划分
  2. 二、生产最小可用拓扑(一期)
  3. 三、不停机升级的标准流程
  4. 四、回滚预案
  5. 五、监控与告警(上线前必须有)
  6. 六、上线前检查清单
  7. 七、二期/三期演进路径