遇到的一个分布式多线程的问题总结

3周前 (09-03) wang JAVA 0评论 已收录 19℃ 浏览数:14

需求背景

分销模型,需要记录A给B贡献了多少分红,以前是通过订单列表去计算。后面修改为新增一张表,记录每个人给每个人贡献了多少销售额、多少分红。订单付款的时候,拿到贡献者A和受益者B,和销售额和分红。对一行数据进行累加。逆向扣减。上线后发现有mysql的重复报警出现,以下是解决问题的描述。
解决的过程描述

上线后发现有mysql的重复报警出现,于是怀疑是多机并发的问题,线上七八台机器,正好kafka是按默认的id分区的,所以重新按照业务id进行的了分区
kafka按业务id分区上线后还是有问题,同一服务器日志查看发现业务上contributorid和distributorid对应的记录同一时间会有多个记录产生,所以就想到了kafka的消息消费是多线程的,于是修改线程参数改为单线程
线程参数修改上线后还是有问题,检查发现只是把线程池的核心线程corePoolSize改为了1,最大线程maximumPoolSize没有修改,默认还是8个线程,于是又把maximumPoolSize改为了1,发布上线
单机单线程上线后还是有问题报警,于是静下心来思考,因为是先读取再插入或更新,还是会有不一致的问题,所以想到了加锁synchronized(distributorUserId + “-” + beneficiaryUserId).intern())的动作(同时最大线程改为8),再次发布上线 其实这个处理跟上一步是一样的,单线程执行跟多线程加锁跟报错没有区别,涉及到的唯一索引的数据,让他单线程执行
唯一键冲突的是还有问题出现,又一次陷入沉思,再此查看日志,终于想到还有主从库的问题(之前有想到,但使用姿势有问题),于是又一次修改,使用主库查询ommission_statistics是否有记录存在
上线后终于正常了
解决该问题的总结

正确设置kafka的分区键,相同的业务分到同一分区处理
核心线程改为1,最大线程改为8,多线程消费的快
使用同步锁,synchronized(distributorUserId + “-” + beneficiaryUserId).intern()),让设计到唯一索引的数据单线程执行,防止乐观锁更新失败
查询唯一键记录是否存在时使用主库查询

博主

Just do it. Now or never.

相关推荐

嗨、骚年、快来消灭0回复。