驽马十驾 驽马十驾

驽马十驾,功在不舍

目录
XXL-Job的核心设计总结
/  

XXL-Job的核心设计总结

參考文章:

优势

传统项目的形式任务可以通过Quartz或者CRON的方式触发,但是如果是集群项目,如果采用传统的方式,就存在如下问题:

  • 一个任务被多个主机同时多次执行的问题
  • 执行异常情况,不支持通知(钉钉、邮件)
  • 任务执行的Dashboard的执行情况记录不够。

用户使用的时候,完全可以将自身作为XXL-Job的任务执行器注册到Admin中

核心设计

整体流程

  • Client根据配置的Admin的地址进行注册,核心是自己的Job信息
  • Admin对任务进行管理,比如:执行间隔、执行参数、Handler选择逻辑、超时时间等
  • 当某个任务的执行时间到时,Admin调用Client,让其进行执行
  • Client执行任务,然后记录信息

调度中心原理

扫描流程

  • while循环进行任务扫描,每次至少1秒时间,应该是为了减少DB压力。
  • 扫描前执行for update做一个排它锁,避免HA部署时候,同一刻任务被调度多次
  • 扫描出下一次触发时间trigger_next_time在5秒内的任务,然后根据不同类型进行处理
    • 当前时间往前推5秒再之前的任务(~,-5) 的任务,直接抛弃
    • 当前时间往前推5秒之内的任务[-5,0],更新下一次触发时间,然后判定该时间是否在本周期内,如果是那么放入时间环
    • 当前时间之后的5秒内的任务[1-5],放入时间环
  • 上述流程处理完成后,都要重新计算Job的下一次执行时间,并将这个时间持久化到DB

调度流程和时间环

  • 时间环是一个60个刻度的Map结构,整体是:Map<Integer, List<Integer>> ringData ,其中Key是触发时间秒戳%60的余数,value是当前秒的任务列表
  • 每隔1秒,获取当前时间秒戳,然后同60求余数,再加上前一秒,然后读取Map,得到任务列表,依次触发

因为任务是放在内存中的,所以加入某个调度器宕机,那么这5秒的任务就丢失了?

  • 当进程被关闭,会判定当前的ringData是否有数据存在,如果有,那么会暂定8秒,等待任务被调度,所以不要利用kill -9 Pid来关闭进程

使用教程

普通使用

  • 项目集成job-core,然后通过注解定义任务
  • 项目提供任务的HTTP接口,然后由一个HttpHandler进行调用
  • 脚本执行

分片模式使用

分片广播模式是指,某个任务,会被分发到所有的执行器中,每个执行器可以获取到totalcurIndex,然后在业务逻辑中根据curIndex自行分片。比如1W条数据,可以通过curIndex分成total份,然后当前的执行器处理curIndex份的数据。

核心问题

  • XXL的Bean Method的异常如何处理?

    • 通过抛出异常进行处理
  • 调度器集群部署如何防止任务重复执行?

    • 通过for update排它锁,任务处理后,更新下次触发时间,然后每次扫描的是下次触发时间在当前时间加5秒前的任务。
  • 关闭调度器是否会导致任务被丢弃

    • 非暴力关闭下,是不会的。因为在desotry方法中判定了ringData是否有数据,如果有,继续等待8秒再进行关机。同时关闭状态设置为了true,也不会继续扫描啦。
骐骥一跃,不能十步。驽马十驾,功在不舍。