批量任务在不同的公司都在使用,如每天定时生成订单、处理特定的任务等等,当数据量一大的时候,批量任务就会变得执行非常慢,有的要跑几个小时,甚至更久,如何来提高批量任务执行的速度呢?方法有多线程+分片,这两种结合起来执行速度是非常快的,单纯使用多线程也会提高处理速度(一般的批量任务偏IO密集型,用多线程会提高处理速度)。
有多个批量处理框架,如Quartz、Spring-batch、Tbschedule、Elastic-job......,本文自己来介绍一种自已设计的分布式轻量极批量任务框架。
![v2-659adc62ed74be388572f865e9535e76_b.jpg](https://i-blog.csdnimg.cn/blog_migrate/d0804e9de0cbe60d11c91085e6920a71.png)
基本的原理如下:
- 选择一个节点作为master节点(一般集群通过前端请求会路由到一台机器上,它就是Master节点),它负责不断从数据源捞数据,并发送mq消息(同一批数据用一条消息发送出去);
- 其它的节点监听消息,有消息过来就进行处理。
上面看上去好简单,先看两个基本的问题。
- 如何捞数据?
- java代码如何执行呢?
答1:一台机器作为Master节点进行捞数据,它必要要做到数据不能重复,拿从Mysql数据库表中捞数据来讲,每次取1000条数据,可以指定一个主键id,对select 结果排序,开始指定这个id集合不会小于0,以后把最后一条数据的id作为下次捞数据的最小id,这样就可以做到数据不会重复。
答2:有同学会问,为什么要讲java代码如何执行呢?直接new出对象不就行了吗?我们是提供界面运行,就是你把写好的代码放到界面中,点击运行就ok了。此时如何来实现呢?其实JDK已经提供了相应的工具来帮忙我们来编译java源码,然后通过自定义的classloader来loadclass到内存中并实例化对象,一定要允许同名的类多次加载,因为有时写错了,再修改,这里的做法有多种,最简单的方法是破坏类的加载机制,每次可以加载,热部署也就是这个道理。
实现暂停、停止的功能,这个也比较简单,每次执行功能时,先从分布式缓存中取该消息对应的开关变量,如果是执行状态,就继续执行,如果是停止状态,就跳过执行;暂停则在Master节点上做,如果发现是暂停状态,则发跳过捞数据逻辑。
上面都理解好了,还有一个问题是如何遇到发版本,机器重启怎么办?我们不怕Worker节点重启,因为开机就会启动消息监听类,数据都存储在mq集群,只要我不去消息它,消息只是堆积,不会丢失。最担心的Master节点挂了,这个问题如何来解决呢?
解决的方法是Master节点在开始执行任务的时候,就注册任务,并任务状态是Running状态,如果正常结束后,任务remove掉,并任务状态是Finish状态。如果是非正常状态,注册中心会感知这个节点的变化,并通知其它的机器节点,任务有异常情况,其它的节点通过分布式锁去获取Master的权力,这里有一点要注意就是上次执行数据到数据主键id值一定要记住,否则就会有问题。
这次先概述的描述整个设计思想,后续会对其中的细节加以分析和介绍。