java刷千万数据_谈java多线程方式刷数据的一点建议

获取要清洗的记录的ID

这里要一次性尽可能多的获取需要处理的纪录数,这里要注意不要获取太多字段,只需要获取主键即可,因为这个ID只是为了给线程分配任务用。每个线程在执行的清洗任务的时候,再查询需要更新的字段即可。

这里有一个坑,也有一个技巧解决这个坑。如果顺序取数据,千万不要使用limit,因为limit 0,10000很快,但是limit 10000,20000就慢了,因为在执行limit 10000,20000的时候,实际上我们需要0到10000之间的数据,但是mysql还是会扫描这些记录的,这样要清洗整个表,而且整个表的纪录是上百万,上千万,那么越往后就越慢,会把mysql服务器搞垮。

如果主键类型是int,并且是递增的,那么就可以使用这个特点,就上面查询下一次要清洗的数据范围的查询sql修改为 where id >= and id < 这样的方式,这样mysql的执行计划的type列就是rang,使用了索引,另外,只是查询ID,而且覆盖了索引,也就不需要回表查询了,很快的。

线程个数

采用线程池,Executors.newFixedThreadPool(16),固定16个线程,16个线程已经很多了,要结合线上机器的core,如果线上的机器是2个core,那么搞16线程,资源都浪费线程之间的竞争和调度上面了。

每个线程执行的任务数不要过大,过大了反而不能压榨线程了,既然搞了16线程,就让每个线程执行的任务数不要过大。

insert 或者update的方式

一般稍大点的(电商)互联网企业,线上使用mysql都是集群的,而且灾备考虑,都会部署多个机房,那么当数据变更时,就会垮机房同步,虽然有机房之间有专线,而且网卡的带宽千兆,但是,为了尽量不对线上业务造成影响,应该尽可能在业务低谷时进行清洗数据。

一般要避免采用批量insert 或者批量update的方式,因为这样会造成锁表现象,应该在java程序端进行单条insert和upate,这里也要主要不要把线上的QPS搞的太高,这就需要进行执行一段,然后sleep下。

保留修改纪录和灰度进行演练

毕竟是操作线上的数据,在灰度环境进行演练是非常必要的。另外,对于修改纪录要存档,不要仅仅通过数据库的操作日志进行回滚是不现实的。

在进行目标表进行清洗的时候,有一种方案比较降低风险,就是采用中转表的方式,在中转表进行清洗,然后进行将表rename到目标表,不过,这里有一个限制,就是在清洗过程中,要保证中转表的数据要和目标表的数据完全一致,因为中转表的数据是来自目标表的。其实,这个就是和MYSQL数据升级是一样的道理,如果mysql一主一从,那么先升级从,升级,切换将从设置为主,然后对主进行升级。道理都差不多!

线程的同步控制 既然一个任务分成很多的子任务,而且每个子任务用一个线程执行,那么一个完整的任务执行完毕了,任务才算真正完成,特别是那种顺序处理或者逻辑中依赖了顺序的清洗,所以,就要控制线程的同步,当所有的线程执行完毕后,才能算作本次任务执行完成。可以使用CountDownLatch来控制线程的同步。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值