MySql在线分库双写方案

表结构:

DROP TABLE IF EXISTS `double_write_test_old`;
CREATE TABLE `double_write_test_old`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `data` int NOT NULL COMMENT '数据',
  `updated_at` datatime,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '双写测试旧表' ROW_FORMAT = Dynamic;

DROP TABLE IF EXISTS `double_write_test_new`;
CREATE TABLE `double_write_test_new`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `data` int NOT NULL COMMENT '数据',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '双写测试新表' ROW_FORMAT = Dynamic;

只存在新增数据
setp 1 开启后台脚本
从旧数据开始往前追;
小批量插入;(一次太多会给旧库和新库太大压力);

脚本停止条件:
直到因已存在而插入失败则停止;

setp 2在线双写

old.insert
insert into double_write_test_old(`data`) value(`data`);
id := select LAST_INSERT_ID();

new.insert (这里可以走异步插入,并不影响主业务性能)
insert into double_write_test_old(id,data) value(id,data);
若存在失败:
若old插入成功,new插入失败;(或者old插入执行完后,宕机);  
此时old的数据较多,new少了一条; 对业务来说没有问题;

setp 3 结束:
如果出现错误或者宕机等情况,重试;
多校验几次后,没有错误出现且满足脚本执行结束条件,就可以结束;
更新服务单写;

存在新增和修改数据
setp 1开启后台脚本
从旧数据开始往前追;

insert into double_write_test_new (`id`,`data`)
values(result.id, result.data, result.updated_at) 
on duplicate key update data = result.data and updated_at < result.updated_at;
此处稍有区别,需要当前的时间大于已存在的才能修改值,防止脚本将新的修改数据覆盖;
时间精度是秒,可以改为更高精度的或者添加版本号处理该问题;

脚本停止条件:

time = 开启双写的那一刻+一段时间(大概估算一个,防止漏数据);
满足 updated_at < time的新旧库数据是一致的;
select * from double_write_test_old where updated_at < time;
select * from double_write_test_new where updated_at < time;
证明在新库数据已经追上了旧库数据;

updated_at 添加索引,并分段;

step 2在线双写
新增的数据:
同上;
修改的数据:

1 old.update
	update double_write_test_old set data = 2 where id = xx;
	result := select * from double_write_test_old where id = 1;

2 new.updateOrInsert(这里可以走异步,并不影响主业务性能)
	insert into double_write_test_new (`id`,`data`)
	values(result.id, result.data, result.updated_at) 
	on duplicate key update data = result.data updated_at = result.updated_at;
	这里都使用old库的时间;

step 3结束:
如果出现错误或者宕机等情况,重试;
多校验几次后,没有错误出现且满足脚本执行结束条件,就可以结束;

上述过程为了加速,添加了索引,需要在事前事后做表结构修改
使用pt-online-schema-change,这里不做过多说明,其核心思想和上述方案相同;

猜你喜欢

转载自blog.csdn.net/weixin_56766616/article/details/130735022