前言 从自建数据库到云数据库的无损迁移方案的设计和实行,是基于以下背景: 在服务流量比较少时,多个模块共服务,共数据库。qps起来后,发现数据库因为热点流量,出现了读写瓶
前言
从自建数据库到云数据库的无损迁移方案的设计和实行,是基于以下背景:
- 在服务流量比较少时,多个模块共服务,共数据库。qps起来后,发现数据库因为热点流量,出现了读写瓶颈。
- 在迁移时,数据库选型为自建还是云数据库。因为运维能力在dba层面比较薄弱,暂时不考虑继续维护数据库生态,而使用云厂商的云数据库组件维护,而旧数据源是使用了自建数据库。并且,云数据库不开放定制化双写设置,内部的迁移计划粒度,也无法细化到某个表,并且做不到业务无损。
- 迁移过程,业务方期望用户无感,流量无损,不接受停机。
PS: 方案数据库选型无关,但本次方案的实行背景,是postgres。所以本次也贴上了过程中用到的命令。
方案设计
无损迁移的过程,核心思路,是如何保证a源和b源,达到相对可靠的双写状态,再基于这个状态,去把读取流量切到b。
操作细节
- 使用数据库底层命令,做到存量数据迁移。
- 使用mq做到,增量数据同步。
- 存量导入节点到mq上报,中间存在同步窗口期,丢数据。这个问题,通过提前上报mq增量数据,再同步存量数据,对修改操作,做到业务幂等,确保一定被执行1次。
原料
pg_dump -U xxxxx -d dbname -t user_prop -h a.a.a.a > /tmp/user_prop.sql
psql -U xxxxx -d dbname -h b.b.b.b < /tmp/user_prop.sql
-- 修正迁移后表的id自增序列基准值
with tmp as (
select max(id)+1 as max_id from user_prop
)
select setval('user_prop_id_seq', tmp.max_id) from tmp;
select max(created_at) from user_prop; -- 根据这个结果减3分钟,做窗口消除边界
执行步骤
a: 旧库 user_prop 表
b: 新库 user_prop 表
- 对a库写入,追加【写a幂等值】.
回滚方案: 不需要回滚
- 开启背包赠送消息存储,对a库保持读写的同时,对写请求,写入mq, 消息追加幂等值。
回滚方案: 不需要回滚
- 对a库user_prop存量,导入b库.
回滚方案: 不需要回滚
- 开启一个消费服务,将mq内的写入,同步到b。并保持持续消费。
回滚方案: 出错严重时,消费时间点往后移,重新导入存量表.
- 待消费积压下来后,此时,a保持可读,a保持自身写入。b保持无读,通过mq写入. 也就是双写可靠了。
- 将读取流量,切到b,确认线上正常.
回滚方案: 读取流量切回a
- 关闭a的写入。
回滚方案: 不需要回滚
- 确认a源不再有user_prop读写流量
- 同步给数据组,user_prop更换了源。
执行进度
事件
当前状态
达成时间
设计方案设计
已完成
2022/3/29 11:40
对a库写入追加mq上报和写入幂等
已完成
2022/3/29 16:00
追加b库异步消费
已完成.
2022/3/29 20:00
双写同步状态一致
已发布
2022/3/30 10:00
读源切b
已发布
2022/3/30 20:00
写源砍a(不影响发布过程)
等待b源读写可靠性验证1礼拜
预计4月8号
流量验证(不影响发布过程)
待定
预计4月8号