贵阳网站推广有几家二手书网站策划书
news/
2025/10/5 10:59:23/
文章来源:
贵阳网站推广有几家,二手书网站策划书,会员中心网站模板,dedecms网站地图模板怎么1.亿级积分数据分库分表#xff1a;总体方案设计 上一篇博客中写了一下积分数据分库分表的总体方案设计#xff0c;里面说了采用应用程序代码双写的方式实现的增量数据同步#xff0c;本篇就对这一块进行一些细化的介绍#xff0c;包括#xff1a;
为什么不用Canal监听数…
1.亿级积分数据分库分表总体方案设计 上一篇博客中写了一下积分数据分库分表的总体方案设计里面说了采用应用程序代码双写的方式实现的增量数据同步本篇就对这一块进行一些细化的介绍包括
为什么不用Canal监听数据库binlog有哪些优缺点吗
为什么要用代码双写有哪些优缺点吗代码双写怎么实现的
Canal监听binlog
实现流程 Canal监听binlog的方案大致流程如下图所示
对原有老的单表添加Canal监听老表的增删改操作会产生binlog通过Canal将binlog转发到kafka消费kafka的消息将增量的数据通过分库分表中间件写的新的分表中对老的单表的创建时间在Canal监听时间点之前的数据全量迁移到新的分表数据核对校验新老表的数据灰度切流验证这一步没有画出来在运行一段时间后发现没有什么数据不一致了并且增量数据同步追上了老表数据就可以将程序的写切到新分表了 上面说了要增量数据同步追上老表数据但是因为应用程序一直在产生新的写操作导致一直有新的binlog产生导致只能无限逼近老的数据而无法追平所以在第4步切写分表之前要将老表先短暂停写一小段时间等binlog消费完就可以切写了。 优缺点
优点 功能逻辑实现简单
缺点
数据增量同步有短暂的秒级延迟切写分表的时候要停写对业务有影响积分应用程序代码没有通过分库分表中间件做过写入操作直接切写分表有很大的风险引入了新的Canal中间件提升了复杂性 正是因为考虑到使用Canal做增量数据同步需要短暂停写对业务有影响还有就是切写分表的风险所以我们这边才没有使用Canal而是采用了代码双写。
代码双写 实现流程
上一篇博客中关于双写有如下的操作步骤
改造双写代码预发测试多种case跑一下双写开关等校验没问题发布上线上线时双写开关默认关闭可以通过配置中心动态开启打开双写开关新表写入失败先忽略因为更新和删除操作会因为新表数据不存在而失败记录双写开始时间点A将老表的积分明细的createTime小于等于双写开始时间点A5分钟防止时间不同步导致少迁移数据预留一些缓冲时间的数据进行全量迁移到分表新老数据全量数据校验查看数据是否一致同时定时任务每隔一小段时间进行增量校验增量数据因为读取新老数据存在短暂时间差可能会瞬时不一致这种数据隔一段时间再次校验多次校验还不一致的数据进行数据订正老表数据覆盖到新表数据改造代码添加双读的逻辑上线读新表的开关默认关闭低流量节点(凌晨过后)进行白名单、灰度切流userId%10000进行验证逐步流量打开持续观察双写开关切到新表保证只写新表也可以继续写老表一段时间或者创建一个新表往老表同步的canal任务方便回滚完成数据迁移方案系统稳定运行一段时间迁移双写代码下线老表进行资源释放
优缺点
优点
增量数据同步延迟比较低切换写新的积分多表时可以直接切换无需停写积分应用程序代码通过分库分表中间件做过各种增删改查操作各种条件case都跑过后面切写分表就没有风险了
缺点
双写逻辑实现起来相对复杂一些
具体实现
双写改造点增、删、改
双写开关有两个通过配置中心实时切换
写老表开关默认开启新表写入没有问题时可以进行关闭也可以继续写一段时间老表写新表开关默认关闭需要开启时打开 新老表的开关同时打开时表示要进行双写
通过配置中心动态进行切换双写期间需要注意的问题如下
对写新表操作需要记录日志
新表不要求一定写成功不影响服务记录错误日志告警通知等有数据校验订正任务兜底 程序双写的逻辑可以通过对mapper接口添加AOP切面拦截到需要分表的mapper的写方法判断需要双写的时候切换数据源双写到新的分表中通过这种方式可以对原有代码基本上实现零侵入。 AOP切面代码大致如下所示
Aspect
Component
Slf4j
public class DoubleWriteMapperAop {SetString shardMapperSet Sets.newHashSet(PointInfoMapper.class.getSimpleName());Around(execution(* com.wkp.sharding.mapper.*.*(..)))public Object doAroundMapper(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {MethodSignature signature (MethodSignature) proceedingJoinPoint.getSignature();Method method signature.getMethod();String clazzName method.getDeclaringClass().getSimpleName();//不用分表的mapper不用特殊处理直接返回if (!shardMapperSet.contains(clazzName)) {return proceedingJoinPoint.proceed();}//双写前和双写时这里写的老表最后切到写分表时这里写的分表Object result proceedingJoinPoint.proceed();//获取当前mapper的方法上有没有加分片写的注解ShardWrite shardWrite method.getAnnotation(ShardWrite.class);//是写方法 threadlocal里面获取到了需要双写的标识if (shardWrite ! null DoubleWriteThreadLocal.needDoubleWrite()) {//切数据源写分表这里执行双写逻辑 proceedingJoinPoint.proceed();}return result;}
} DoubleWriteThreadLocal.needDoubleWrite()DoubleWriteThreadLocal是个ThreadLocal里面获取到是否需要双写的标识这个ThreadLocal的值是前面通过配置中心判断是否双写开关开着如果开着双写会将ThreadLocal的双写标识设置为true。 AOP切面这里通过ThreadLocal判断而没有通过读取配置中心原因是可能前面配置中心打开了双写但是执行到切面时恰好配置中心将开关从双写切到写分表了那么这里就不会双写分表了分表就会丢失一条数据。 后面切写的时候直接通过配置中心切换开关即可动态切换只写到分表中。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/928155.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!