关于 migration-planner
帮助负责生产环境迁移的团队规划低停机迁移。它组织分阶段发布、数据验证、风险控制和回滚方案。
主要功能
- 01功能标记与蓝绿部署模式
- 02双写和回填规划
- 03数据验证策略
- 04各阶段回滚方案
- 05风险与沟通规划
适用场景
- 01规划数据库迁移
- 02逐步切换读取流量
- 03准备验证和回滚步骤
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ patricio0312rev/ skills --skill migration-planner安装后在 Claude Code 中输入/migration-planner确认已加载。
详细介绍
迁移规划器
执行安全、零停机的迁移,并制定验证和回滚计划。
迁移模式
1. 功能标记迁移(最安全)
Phase 1: Deploy new code (disabled)
Phase 2: Enable for 1% traffic
Phase 3: Ramp to 10%, 50%, 100%
Phase 4: Remove old code
2. 双写迁移
Phase 1: Write to both old and new
Phase 2: Backfill old → new
Phase 3: Read from new (write both)
Phase 4: Stop writing to old
Phase 5: Decommission old
3. 蓝绿部署
Blue (current) → Green (new)
Switch traffic: Blue → Green
Rollback available: Green → Blue
完整迁移计划模板
# Migration Plan: MySQL → PostgreSQL
## Overview
**What:** Migrate user database from MySQL to PostgreSQL
**Why:** Better JSON support, improved performance
**When:** Q1 2024
**Owner:** Database Team
**Risk Level:** HIGH
## Current State
- MySQL 8.0
- 500GB data
- 100K users
- 1000 writes/min
- 10,000 reads/min
## Target State
- PostgreSQL 15
- Same data model
- No downtime
- Data validation 100% match
## Phases
### Phase 1: Dual Write (Week 1-2)
**Goal:** Write to both databases
**Steps:**
1. Deploy PostgreSQL cluster
2. Create schema in PostgreSQL
3. Deploy dual-write code
4. Enable dual writes (MySQL primary, PostgreSQL secondary)
**Code:**
```typescript
async function createUser(data: CreateUserDto) {
// Write to MySQL (primary)
const mysqlUser = await mysql.users.create(data);
// Write to PostgreSQL (secondary, fire and forget)
postgres.users.create(data).catch((err) => {
logger.error("PostgreSQL write failed", err);
});
return mysqlUser; // Still trust MySQL
}
```
验证:
- 监控 PostgreSQL 写入成功率
- 每日比较行数
- 如果数据偏差 >0.1%,则发出警报
回滚: 禁用 PostgreSQL 写入
阶段 2:回填(第 3-4 周)
目标: 复制历史数据
步骤:
- 创建 MySQL 快照
- 分批运行回填脚本
- 验证数据完整性
- 失败后自动恢复
脚本:
def backfill():
last_id = get_last_migrated_id()
batch_size = 1000
while True:
users = mysql.query(
"SELECT * FROM users WHERE id > %s LIMIT %s",
[last_id, batch_size]
)
if not users:
break
postgres.bulk_insert(users)
last_id = users[-1]['id']
save_checkpoint(last_id)
time.sleep(0.1) # Rate limit
验证:
- 行数匹配
- 随机抽样比较(1000 行)
- 校验和比较
回滚: 删除 PostgreSQL 数据
阶段 3:双读(第 5 周)
目标: 验证 PostgreSQL 读取
步骤:
- 部署影子读取代码
- 从两边读取(MySQL 为主)
- 比较结果
- 记录不匹配项
代码:
async function getUser(id: string) {
const mysqlUser = await mysql.users.findById(id);
// Shadow read from PostgreSQL
postgres.users.findById(id).then((pgUser) => {
if (!deepEqual(mysqlUser, pgUser)) {
logger.warn("Data mismatch", { id, mysqlUser, pgUser });
metrics.increment("migration.mismatch");
}
});
return mysqlUser; // Still trust MySQL
}
验证:
- 不匹配率 <0.01%
- PostgreSQL 查询性能可接受
回滚: 移除影子读取
阶段 4:切换读取流量(第 6 周)
目标: 从 PostgreSQL 读取
步骤:
- 功能标记:从 PostgreSQL 读取(1% 流量)
- 监控错误和延迟
- 逐步增加:1% → 10% → 50% → 100%
- 继续写入两边
代码:
async function getUser(id: string) {
if (featureFlags.readFromPostgres) {
return postgres.users.findById(id);
}
return mysql.users.findById(id);
}
验证:
- 错误率没有变化
- 延迟 p95 <500ms
- 没有用户投诉
回滚: 关闭功能标记
阶段 5:停止 MySQL 写入(第 7 周)
目标: PostgreSQL 现在作为主数据库
步骤:
- 停止写入 MySQL
- 保持 MySQL 运行(只读)
- 监控问题
代码:
async function createUser(data: CreateUserDto) {
return postgres.users.create(data);
// No longer writing to MySQL
}
验证:
- 所有操作正常运行
- MySQL 未收到写入
回滚: 重新启用 MySQL 写入
阶段 6:停用(第 8 周)
目标: 移除 MySQL
步骤:
- 归档 MySQL 数据
- 关闭 MySQL 集群
- 移除 MySQL 客户端代码
回滚: 不可用(不可逆点)
验证策略
数据完整性检查
def validate_migration():
# Row counts
mysql_count = mysql.query("SELECT COUNT(*) FROM users")[0]
pg_count = postgres.query("SELECT COUNT(*) FROM users")[0]
assert mysql_count == pg_count
# Random sampling
sample = mysql.query("SELECT * FROM users ORDER BY RAND() LIMIT 1000")
for row in sample:
pg_row = postgres.query("SELECT * FROM users WHERE id = %s", [row['id']])
assert row == pg_row
# Checksums
mysql_checksum = mysql.query("SELECT MD5(GROUP_CONCAT(id, email)) FROM users")
pg_checksum = postgres.query("SELECT MD5(STRING_AGG(id::text || email, '')) FROM users")
assert mysql_checksum == pg_checksum
回滚计划
阶段 1-3 回滚(简单)
- 禁用 PostgreSQL 写入
- 不影响用户
- MySQL 中的数据仍然有效
阶段 4 回滚(中等)
- 切换功能标记
- 将读取路由回 MySQL
- 对用户的影响很小(几秒钟)
阶段 5+ 回滚(困难)
- 必须重新启用 MySQL 写入
- 可能丢失数据(阶段 5 之后的写入)
- 需要恢复双写
风险缓解
风险 1:数据丢失
缓解措施:
- 验证完成前保持双写
- 捕获事务日志
- 持续备份
风险 2:性能下降
缓解措施:
- 对 PostgreSQL 进行负载测试
- 优化查询
- 使用连接池
风险 3:架构差异
缓解措施:
- 架构验证脚本
- 在预发布环境中测试迁移
- 记录数据类型差异
沟通计划
利益相关方更新
**Week 0:** Migration announced
**Week 2:** Phase 1 complete (dual writes)
**Week 4:** Backfill complete
**Week 6:** Traffic shifted to PostgreSQL
**Week 8:** Migration complete
状态仪表板
- 当前阶段
- 数据同步状态(%)
- 验证结果
- 错误率
测试计划
迁移前测试
- 在开发环境中测试
- 在预发布环境中进行完整迁移
- 对 PostgreSQL 进行负载测试
- 验证回滚流程
迁移期间
- 持续监控
- 自动验证
- 手动抽查
- 用户验收测试
最佳实践
- 小批次:逐步迁移
- 双写:保持两个系统同步
- 功能标记:控制发布
- 持续验证:不要轻信,务必验证
- 做好回滚准备:为最坏情况做好计划
- 密切监控:跟踪指标
- 经常沟通:及时告知利益相关方
输出检查清单
- 已定义迁移阶段(5-7 个阶段)
- 双写实现
- 回填脚本已就绪
- 验证策略
- 已配置功能标记
- 各阶段的回滚计划
- 风险缓解策略
- 沟通计划
- 监控仪表板
- 测试检查清单
评论
支持 Markdown