基于XXL-JOB二次开发的分布式定时任务调度平台

关注“Java艺术”一起来充电吧!

XXL-JOB是一个代码开源的分布式定时任务调度平台。XXL-JOB支持多种模式执行定时任务,如直接执行任务脚本代码、通过commandJobHandler调用任务接口、使用@XxlJob注解注册JobHandler

基于XXL-JOB二次开发的分布式定时任务调度平台_第1张图片

我们旧的定时任务项目是通过提供接口由XXL-JOB定时调用commandJobHandler,再由commandJobHandler执行shell命令调用接口完成,虽然不是直接调用接口,但也可以说接口就是定时任务。

这种方式有利也有弊。团队成员可能在编写接口时,疏忽了接口执行耗时带来的影响,如因项目设置http超时导致XXL-JOB认为任务执行失败,或是每个接口都需要手动将任务放入线程池异步执行,意味着任务执行成功或是失败XXL-JOB将无法得知,放入自定义的线程池执行日记无法被XXL-JOB收集。我们也想将一些耗时、耗内存的任务实现分片执行,让定时任务项目能够支持横向扩展。

为解决这些问题,我们考虑将定时任务项目重构,并由原来的SSM框架切换到Spring Boot框架。但由于旧项目已有七八十个定时任务,全部迁移到新的框架上不现实,因此我们也放弃替换其它分布式定时任务调度框架的想法,转而想通过基于XXL-JOB进行二次开发,解决我们在定时任务上遇到的一些问题。

xxl-job-onion

XXL-JOB-Onion now means XXL-JOB eXtensions. :)

XXL-JOB-Onion 是基于XXL-JOB的二次开发,加入一些定制化功能。


1

二次开发添加的功能

基于XXL-JOB 2.2.0版本进行二次开发

  • 添加ONION_BEAN运行模式,强制使用分片策略;

  • ONION_BEAN模式改用线程池执行任务;

  • ONION_BEAN模式的阻塞处理策略放弃单机串行策略;

  • 告警模块实现告警等级区分,一级告警短信发送;

  • ONION_BEAN模式提供@NotNeedShard注解,当使用注解声明任务不需要分片执行时, 如果执行器的可用数量大于1,则使用一致性HASH路由策略;


2

关于ONION_BEAN模式的疑问

  • 为什么添加ONION_BEAN模式?ONION_BEAN运行模式与其它运行模式有什么不同?

基于XXL-JOB二次开发的分布式定时任务调度平台_第2张图片

使用BEAN运行模式可通过在方法上添加@XxlJob将任务注册到admin,但这种方式对开发人员的约束不够强力,给开发人员自由可能就会给项目后期水平扩展节点实现任务分片执行带来更多的难题。因此,我们放弃了XXL-JOB提供的BEAN模式,添加新的ONION_BEAN运行模式。

为了实现让团队成员开发定时任务时,必须通过实现接口来开发JobHandler。除了在接口参数上强制开发者考虑任务分片执行外,还有一个目的就是限制一个类只能写一个Job。我们旧的定时任务项目很多类都是几千行代码的,一堆的任务在一个类中,失去了代码的可读性。因此使用实现接口的方式还能强制一个类只能编写一个定时任务,在框架层实现代码可读性。当然,缺点就是类增多。

基于XXL-JOB二次开发的分布式定时任务调度平台_第3张图片

ONION_BEAN模式强制考虑任务分片是出于让定时任务项目支持水平扩展的考虑,也支持将一个重的定时任务项目按业务拆分。随着集团内部业务的发展, 后期定时器会越来越多,并且任务处理的数据量也会越来越大。任务分片执行为项目带来扩展性的同时,分片执行可让多台机器分担一台机器的工作,提升任务的完成速度,从而避免一个任务的执行卡到下一个周期,导致原本多个周期的任务堆积在一个周期下执行的情况。比如12:3012:3512:40三个周期的任务由于第一个周期没执行完,后面的任务都在等待,这对一些实时性要求高的任务是个痛点。

ONION_BEAN模式改变XXL-JOB原有运行模式为每个任务创建一个线程的做法,改为使用非固定线程池执行JobHandler。我们都知道,在有限资源,如CPU、内存的情况下,线程数会有一个临界点,超过这个临界点时,再添加线程适得其反。因此使用线程池,可在线程池满后拒绝任务的提交,让该分片任务路由到其它空闲节点上执行,遗憾的是XXL-JOB的分片模式现在还不支持这点,我们计划在XXL-JOB-ONION的后续版本支持。

  • 为什么强制当使用ONION_BEAN运行模式时只能选择分片执行策略?

ONION_BEAN运行模式把需要分片执行的任务与不需要分片执行的任务的考虑权重互换了,通过约定开发JobHandler时必须通过实现接口的方式,在接口的方法上添加分片参数,强调团队开发人员在开发定时任务JobHandler时,需优先考虑让任务支持分片执行。

  • 既然要强制使用分片策略,又提供@NotNeedShard注解支持任务单机运行,这看似很矛盾,为什么这么做呢?

选择ONION_BEAN运行模式,执行策略必须选择分片策略。但由于不是所有任务都需要分片执行,如果不需要分片执行的情况下,还使用分片策略路由,那么会导致所有的不需要分片执行的任务都被分配到同一台机器上执行,导致某个执行器所在的机器资源消耗过大,因此,我们为不需要分片执行的任务提供@NotNeedShard注解,当任务有@NotNeedShard注解时,且执行器的可用数量大于1时,不走分片路由逻辑,而是使用一致性HASH路由。

基于XXL-JOB二次开发的分布式定时任务调度平台_第4张图片

3

告警模块做了哪些修改?

告警模块实现等级区分,一级告警发送短信通知,二级告警发送邮件通知,其它告警当前处理策略为忽略,后续可能将多个三级告警合并为一个告警发送邮件通知。同一个任务如果升级到一级告警,且后续还连续失败,也只会触发一次短信发送。

当前是如何区分告警等级的?每个任务都会有一个告警等级的升级过程:

  • 如果周期为秒钟,则判断是否连续失败60次及以上,是则升级为二级告警;

  • 如果周期为分钟,则判断是否连续失败3次及以上,是则升级为二级告警,连续失败5次及以上升级为一级告警;

  • 如果周期为小时,则判断是否连续失败1次及以上,是则升级为二级告警,连续失败3次及以上升级为一级告警;

  • 如果周期为一天或以上,直接升级为一级告警。

告警等级的评判由评判器实现,并使用责任链模式(或者说是过滤器)支持多个评判器共存。评判器支持排序,目前仅提供OnionAlarmLevelAdjudicator告警等级批评器,如果想要覆盖OnionAlarmLevelAdjudicator评判器,可自行添加告警等级评判器,将排序值设置比OnionAlarmLevelAdjudicator评判器的排序值小即可,OnionAlarmLevelAdjudicator的排序值默认为整型的最大值。

4

XXL-JOB分片策略的实现

XXL-JOB的分片调度策略实现非常简单,分片总数就是当前注册的集群节点数量,通过for循环调用所有节点执行任务。

当一个任务执行完成时,会异步回传任务的执行结果,XXL-JOB通过回传的结果判断一个任务是否执行成功。当任务回传结果为失败时,根据是否配置失败重试次数,决定是否需要重新触发任务执行。在分片模式下,也会为每个分片任务添加一条XxlJobLog记录,当某个分片执行失败时,重试策略只重试失败的分片。

5

我们的执行器项目代码开发规范

定时任务开发规范

  • 按业务分包,如订单相关定时器存放order包;

  • 定时任务需实现OnionShardingJobHandler接口,参考DemoJob

  • 确定不需要分片执行的定时任务使用@NotNeedShard注解声明,参考NotNeedShardDemoJob


单元测试规范

  • 每个定时任务对应一个测试类或者每个业务对应一个测试类,测试类所在包名与源码所在包名保持一致;

  • 定时任务必须经过单元测试通过后才能提交代码;


END

目前尚处于测试阶段,两天时间从开始看源码到改好测试!

基于XXL-JOB二次开发的分布式定时任务调度平台_第5张图片

公众号:Java艺术

扫码关注最新动态

你可能感兴趣的:(基于XXL-JOB二次开发的分布式定时任务调度平台)