该片文章主要是记录下最近关于任务管理的一些想法吧,项目中使用的任务多了,有不少缺点,就想实现一个更好的,但目前只是有点思路,至于后路如何,估计会流产吧。
目前项目中的任务实现方式
任务分类:
- 非定时任务:需要实时判断是否有待执行任务,有则立即执行。例如发送验证码,当检查到有待发送时执行发送操作。
- 定时任务:在某个固定时间或按某个固定周期/间隔执行的任务。例如同步历史数据,每天23:59分执行。
针对非定时任务实现手段:
- 编写单独的main方法,创建shell脚本执行。
- 随项目启动,项目启动时调用某个init方法。
- 如果是并行任务,则创建多个进程。为了便于扩展,总进程数和当前分配的进程号等参数动态传递给main方法,在方法里面通过取模等实现不同进程间数据隔离。
目前我所在项目中普遍采用创建shell脚本执行。
缺点:
- 每编写一个任务,就需要编写shell,导致服务器上一堆.sh脚本,增加维护成本,每次上线都需要重启。
- 针对多进程任务,一般进程号等参数是编写在shell脚本中传递给main方法的。如果现在增加一个进程处理,由于要修改总进程数和指定当前进程的处理进程号,需要修改shell脚本要将之前的进程全部重启,影响很大;当然也可以将总进程号配置在数据库中,但是修改数据库的风险也不小。
针对定时任务实现手段:
- 使用Timer或scheduleThreadExcutor等原生java编写
- 使用Quarz等第三方框架。
我所在项目是使用的基于Quarz自己二次开发的框架,相比Quarz的优点是将任务的配置信息存放到数据库和缓存中了,如果需要修改某个数据库的执行时间,只需要修改数据库相关信息,然后刷新缓存就可以了,无需重启服务器。
但该方法也有缺点,如果是直接使用的配置文件,服务器还不支持热部署,那就比较麻烦了,每次修改都需要重启项目;即便是基于数据库的,修改数据库的风险也很大,且不说是否有权利修改等。
总体缺点:
- 修改配置不方便。
- 并行任务,扩展不方便。
- 管理困难,一堆sh脚本,维护成本高。
- 处理结果不透明,发生异常时,运维人员无法立刻知晓。
- 没有统计信息,无法具体知晓某个服务器或任务等执行了多少次,失败率是多少,成功率是多少。
- 针对定时任务,无法快速的触发一次。
- 无操作记录信息。
针对以上缺点,想开发一个方便管理,易于使用的任务处理框架,意在解决上述缺点。
基于zk的任务处理框架
使用该框架,对开发人员来说可能不会有什么显著影响,之前该写的业务逻辑还是需要写的,如果非要说有什么影响,那就是你可以直接写对应的业务代码,无需关心任务的具体处理流程。该框架主要是减轻运维人员的工作量,提供了很多直观的WEB功能,增加灵活性和扩展新。
理想情况:
开发人员下载客户端Jar包,实现相应接口,开始编写具体的业务逻辑代码,仅此而已,无需再关系任务的具体处理细节。运维人员登陆WEB端界面,设置某个Task的执行计划。OK,至此该Task就可以工作了。
WEB端功能:
- 创建,删除和修改Task。
- 创建Task时:
2.1. 允许设置任务的执行计划,定时,固定周期,固定间隔等。
2.2. 允许设置任务处理计划,并行处理,单独处理等。
2.3. 允许指定具体服务器执行。
2.4. 允许单次触发。
2.5. 允许设置发生异常时的通知方式,短信,钉钉等。 - 统计功能,展示某个Task对应的服务器的执行情况,包括:执行次数,成功率等信息。
- 监控功能,上次执行情况。
- 操作记录,每一次操作都需要记录日志。
- 安全。功能授权等信息。
客户端JAR功能
- 提供相应的接口,供开发人员使用。
- 向ZK注册TASK。
- 针对并发任务,当新增服务器时,自动感知并更改该任务的服务集的入参,例如总进程数,每个服务分配的进程号等信息。
- 获取可用服务集,针对并发处理任务,分发出去。
原理:
主要是基于ZK提供的通知机制,在某个节点设置监视点,由服务端主动通知该节点下的所有客户端。