Fork me on GitHub

版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | http://vearne.cc

1.前言

xuxueli/xxl-job是一个分布式任务调度平台。它在github上有1w多个star,有多家公司都已经用在生产实践中。

在萌叔看来这是一个”Less is more”的典型。它的设计的非常简单,最大的优点是实用。

2.主要结构和逻辑

XXL-JOB任务调度平台分为2个部分,SchedulerExecutor。具体的实现Scheduler对应是xxl-job-admin,同时xxl-job-admin还配有web UI,可以配置管理任务。

SchedulerExecutor之间通过HTTP API交互,因此Executor可以通过各种语言实现。比如Golang的
xxl-job/xxl-job-executor-go

时序图

以上图为例,scheduleThread将任务通过Executor是的/run api推送给Executor

{
    "jobId": 3,
    "executorHandler": "task.test",
    "executorParams": "x=100",
    "executorBlockStrategy": "SERIAL_EXECUTION",
    "executorTimeout": 0,
    "logId": 17,
    "logDateTime": 1606100913829,
    "glueType": "BEAN",
    "glueSource": "",
    "glueUpdatetime": 1606099566000,
    "broadcastIndex": 0,
    "broadcastTotal": 1
}

Executor会根据executorHandler找到对应的handler,执行完之后,又会调用xxl-job-admin/xxl-job-admin/api/callback回报任务的执行结果。从上面的描述我们可以知道,xxl-job-adminexcutor都必须暴露出api服务(都是HTTP接口)。

Scheduler可以有多个。它们之间通过MySQL进行同步。
主要的调度逻辑在JobScheduleHelper

在每一轮执行调度逻辑之前, Scheduler必须先获得行锁

while (!scheduleThreadToStop) {
 ...  
 // 加行锁
try {
preparedStatement = conn.prepareStatement(  "select * from xxl_job_lock where lock_name = 'schedule_lock' for update" );
                        preparedStatement.execute();
 ...                      
} catch (Exception e) { ... } finally {

  ...
  // 注意:锁必须正常释放
  conn.commit();
  ...
}

由于xxl_job_lock 表中只有一条记录,所以这个逻辑与请求表锁类似,开销是比较大的。

其实这里还可以利用分治法的思想,让不同的任务对应到不同的行锁。来提高整体的并发度。依萌叔的推测, xxl-job 设计时考虑就是调度任务的数量不会太多。因此性能不是它的最主要关注点。

3. 其它

xxl-job内部没有使用Zookeeper这种数据库,因此在高可用性上与Quartz相比还是会稍微弱一些。好在它依赖少,搭建、学习的成本就会非常低。让萌叔不经想到了《鹿鼎记》。

澄观微笑道:「师侄从十一岁上起始练少林长拳,总算运气极好,拜在恩师晦智禅师座下,学得比同门师兄弟们快得多,到五十三岁时,於这指法巳略窥门径。」–《鹿鼎记》

注意: 对MySQL而言,如果xxl-job-admin在持有行锁的期间发生异常退出,与MySQL的连接断开。一段时间之后,MySQL会自动主动释放这个行锁。因此并不会出现死锁的问题。

4. 参考资料

1.分布式任务调度平台的研究


打赏我

微信支付码

1 对 “分布式任务调度平台xxl-job”的想法;

发表评论

邮箱地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据