XXL-JOB:分布式任务调度的破局者

108 阅读4分钟

01 传统任务调度的四大痛点

项目中的定时任务你们是怎么实现的呢?是使用Timer@ScheduledSchedulingConfigurer 还是Quartz

为了提高系统的可用性,大部分公司都会采用多节点的部署方式。那么问题来了,定时任务的被触发,是不是意味着多哥节点同时再执行相同的任务,可能会造成数据的重复统计或者计算。

为了解决上述业务的痛点,幂等性的设计尤为重要。通过分布式锁、数据库锁或者其他方式,保证了最终结果的唯一性。

这就是传统的任务调度方式。单纯的依赖程序员的经验避免问题的产生,并不能保证任何一个人都能做到。下面来总结一下传统任务调度的痛点。

  • 单点故障风险: 传统单机定时任务一旦宕机,所有任务停止,业务面临瘫痪
  • 缺乏可视化管控: 任务状态需登录服务器查看日志,故障定位效率低下
  • 资源分配不均: 固定节点执行或者全部同时执行导致负载失衡,高峰期容易引发雪崩。
  • 扩展能力薄弱: 新增任务需重新部署代码,无法适应快速迭代需求

02 XXL-JOB简介

为了避免重复造轮子,有没有框架级别的第三方框架解决呢?当然有。下面就是我们的今天的主角XXL-JOB

官网:www.xuxueli.com/xxl-job/

XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。

2.1 与传统任务调度方案的对比

优势维度传统方案XXL-JOB解决方案
高可用性单点部署风险高调度中心集群+执行器动态注册
弹性扩展需人工干预扩容自动识别新节点,秒级生效
运维效率依赖Shell脚本+日志排查可视化控制台,实时监控任务轨迹

2.2 技术亮点

  • 秒级任务触发(通过时间轮算法优化)
  • 智能路由策略(支持分片/故障转移/忙碌转移)
  • 跨语言支持(通过HTTP协议对接任意语言执行器)

2.3 架构思维

image-20250319161951111

  • 调度中心:独立的调度中心,管理所有的执行器和调度任务
  • 执行器:采集并管理所有调度的任务
  • 任务控制台:最小颗粒度的调度任务控制台

简单来说就是:调度中心管理的包含许多执行器,执行器包含了许多调度任务。

2.4 设计哲学

去中心化调度

  • 调度中心不持有业务逻辑
  • 执行器自主管理任务线程池

最终一致性保证

  • 异步回调机制
  • 补偿性日志同步

熔断降级策略

  • 执行器过载保护(队列阈值)
  • 调度中心限流控制

2.5 任务执行流程

  • 任务注册:执行器启动时向调度中心注册地址
  • 触发调度:Admin通过Quartz扫描待触发任务
  • 路由选择:根据策略选择目标执行器实例
  • 任务执行:Executor通过本地线程池执行任务
  • 结果回调:通过异步线程上报执行状态
  • 日志追踪:控制台实时展示全链路日志

03 典型应用场景

简单来讲,凡是需要定时任务的地方,基本上都可以使用XXL-JOB。我们来看下具体的场景有哪些?

3.1 电商领域

  • 库存同步:每小时全量同步ERP库存数据
  • 风控扫描:每10分钟检测异常交易行为
  • 数据推送 :订单成交后,部分数据需要推送失败,需要重推
  • 数据一致性:定时同步缓存和数据的数据,保证数据一致性

3.2 金融系统

  • 日终对账:交易日结束后自动触发资金核对
  • 报表生成:凌晨3点批量生成监管报送文件
  • 利息计算:每日定时计算用户账户收益

3.3 物联网(IoT)

  • 设备巡检:每5分钟轮询万台设备状态
  • 数据清洗:TB级传感器数据夜间批量处理

04 项目中的使用

4.1 项目引入

<!-- http://repo1.maven.org/maven2/com/xuxueli/xxl-job-core/ -->
<dependency>
    <groupId>com.xuxueli</groupId>
    <artifactId>xxl-job-core</artifactId>
    <version>${最新稳定版本}</version>
</dependency>

4.2 配置

/**
 * xxl-job config
 *
 * @author xuxueli 2017-04-28
 */
@Slf4j
@Configuration
public class XxlJobConfig {

    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;

    @Value("${xxl.job.executor.appname}")
    private String appName;

    @Value("${xxl.job.executor.ip}")
    private String ip;

    @Value("${xxl.job.executor.port}")
    private int port;

    @Value("${xxl.job.accessToken}")
    private String accessToken;

    @Value("${xxl.job.executor.logpath}")
    private String logPath;

    @Value("${xxl.job.executor.logretentiondays}")
    private int logRetentionDays;

    @Bean(initMethod = "start", destroyMethod = "destroy")
    public XxlJobSpringExecutor xxlJobExecutor() {
        log.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppName(appName);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
        log.info(">>>>>>>>>>> [adminAddresses]{}|[appName]{}|[ip]{}|[port]{}|[accessToken]{}|[logPath]{}|[logRetentionDays]{}",
                adminAddresses,appName,ip,port,accessToken,logPath,logRetentionDays);
        return xxlJobSpringExecutor;
    }

4.3 任务定义

@Component
@JobHandler("xxxHandler")
public class XxxHandler extends IJobHandler {

    @Override
    public ReturnT<String> execute(String param) throws Exception {
		// 业务逻辑编写
        return SUCCESS;
    }
}

4.4 管理平台增加调度任务

4.5 小结

引入XXLJOB之后,后续开发只要操作4.34.4即可订制自己的定时任务。


喜欢就点赞收藏,也可以关注我的微信公众号:编程朝花夕拾

公众号