个人随笔
目录
架构设计思考20240815:关于后台处理批量任务的解决方案的一点点思考
2024-08-15 15:40:31

一、业务场景

在开发中,我们总是会遇到类似批处理的需求,比如批量发送短信,批量下载文件,批量同步数据,批量分析结果等。这些需求通常有一个特点,那就是耗时却没那么急,比如有些数据统计是在凌晨统计完,白天才需要查看。

但是也有些也比较急,比如订单同步,第三方订单同步过来,我们要对订单进行分析计算业绩送权益等。那我们常用的解决方案是啥呢?

二、解决方案分析

对于这种批处理需求,无非就是根据时间邀求,如果不急的,且数据量不大,那么单线程处理即可。如果时间邀求比较高,数据量又大,那么就需要用多线程。需要注意的是,不管是单线程还是多线程,都避免不了同一条记录会多次处理的情况,比如程序蹦了要重启,处理超时重试等,所以一定要考虑幂等的情况。

三、单线程处理方案

单线程就比较简单了,就用一个线程跑,没有并发问题,比如一下查询1000条数据处理,处理完后更新状态,再查询一千条数据处理,这种没什么好说的。

四、多线程处理方案

多线程,我们可以起N个线程同时处理,比如每个线程处理50条记录。那么数据怎么取,怎么防止重复处理呢?可以根据如下步骤解决
1、在表中增加两个字段(线程ID和处理时间)
2、每个线程行锁随机获取50条(按业务指定)未处理的数据,获取成功后将线程ID和时间更新为本线程的ID和当前时间,修改状态为处理中,提交事务。
3、重新更具线程ID查询出来处理,处理完后将状态改为已处理。

对于Oracle可以用

  1. select * from xxx where status='0' and rownum<50 for update

对于Mysql和PG可以用

  1. select * from xxx where status='0' and limit 50 for update

原理是:若这50条数据被另一个线程for update中,则会阻塞,等另一个线程提交事务后,本线程即可获取新的50条数据。并且这种批处理任务,通常都是处理耗比较耗时的,通常不会出现某一个线程一直阻塞获取不到数据的情况,就是有也不影响,反而证明数据处理效率高,我们可以减少线程。

线程奔溃处理是怎么办?

我们可以起一个单线程,定时监控处理时间超过实际可能执行的时间的数据,将线程ID和处理时间清空。这里也不用担心可能线程还在处理中的情况,比较程序逻辑上会保证幂等性,重复处理也不会出问题。

当然我们也可以不起一个线程做这个监控,直接查询处理时间超过多久的也当作未处理的即可。

五、单线程改进方案

我们其实可以单线程获取数据,然后多线程处理数据,步骤如下。
1、单线程获取1000条数据
2、将1000条数据拆分成20个线程,一个线程处理50条
3、用Java的CountDownLatch监控等所有线程都处理完后再读取下一批。

不过上面也会遇到某一个线程阻塞一直处理不完的情况,此时可能就需要加上超时时间这种判断逻辑。

六、总结

1、推荐使用单线程批处理任务
2、如果一定要使用多线程,注意处理超时问题
3、逻辑设计要考虑幂等性

 32

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2