XXL-JOB本身不直接扛千万级任务,关键在于任务设计、调度分片、执行隔离和资源管控四点:统一JobHandler+参数化、分片广播+动态扩缩容、执行器线程池隔离+超时控制、调度中心MySQL集群+快慢队列分离。

千万级定时任务不卡死,关键不在 XXL-JOB 本身扛不扛得住,而在于任务设计、调度分片、执行隔离和资源管控四点是否到位。XXL-JOB 是轻量级调度中心,原生支持分片广播、失败重试、路由策略等能力,但若直接把千万个 JobHandler 堆进去,不加治理,调度中心和执行器都会迅速雪崩。
任务聚合:别让“千万任务”真变成千万个 JobHandler
真实业务中,99% 的“千万级任务”本质是参数不同、逻辑相同的批量作业(比如给一千万用户发推送、清理一千万订单的过期数据)。硬编码一千万个 JobHandler,调度中心元数据爆炸,数据库锁表、内存溢出、心跳超时全来。
- 统一注册一个 JobHandler(如
userPushJobHandler),所有任务共用 - 任务参数通过
jobParam传入(如{"batchId":"20241105_001","start":0,"size":10000}) - 后台用分页/游标/时间范围等方式切分数据,避免单次查千万条
- 配合分布式锁或幂等表,防止同一 batch 被重复触发
分片广播 + 动态扩缩容:把压力摊到多台执行器上
单台执行器扛不住千万级处理,必须靠分片把负载打散。XXL-JOB 的分片广播模式天然适配这类场景。
- 调度中心发起分片广播,自动把
shardingTotalCount=100、shardingItem=0~99分发到各执行器实例 - 每个执行器只处理自己分片对应的数据子集(如
userId % 100 == shardingItem) - 执行器节点可动态增减:新增机器后,下次调度自动参与分片;下线机器,其余节点自动承接其分片
- 注意:分片键要均匀(避免数据倾斜),推荐用主键哈希或业务 ID 取模,不用时间字段
执行器资源隔离:防止单个任务拖垮整个 JVM
即使分片了,一个慢任务(如某分片查了 50 万行未加索引)也可能吃光线程池、占满 CPU 或撑爆堆内存,连带影响其他分片甚至心跳上报。
立即学习“Java免费学习笔记(深入)”;
- 为每个 JobHandler 配独立线程池(非共用
xxl.job.executor.corePoolSize),限制最大并发数 - 设置合理超时:
xxl.job.executor.timeout=300(秒级),超时强制中断(需配合Thread.interrupt()或 SQL QueryTimeout) - 大查询加 LIMIT 和游标分页,禁用
OFFSET;写操作拆成小事务(每 1000 条 commit 一次) - 关键步骤打日志 + 上报执行进度(如用
XxlJobHelper.log("processed: {}/{}", done, total)),便于监控和断点续跑
调度中心高可用与降级:别让调度器成单点瓶颈
千万级任务意味着每秒可能有数十次调度请求。默认单节点 H2 数据库 + 内存任务队列必然扛不住。
- 生产必须切换 MySQL(建议 5.7+),开启读写分离,调度日志表按月分表(
xxl_job_log_202411) - 部署至少 2 个调度中心节点,通过 DB 主键或 Redis 实现选主,避免脑裂
- 配置
xxl.job.admin.triggerpool.fast.max=1000和xxl.job.admin.triggerpool.slow.max=200,快慢队列分离,防慢任务阻塞新调度 - 极端情况可临时关闭非核心任务的自动触发,或改用
BEAN模式手动触发,保留调度中心基本能力
不复杂但容易忽略:很多卡死问题其实出在数据库连接池没调优、MySQL 慢查询没索引、JVM 没开 GC 日志定位内存泄漏。先确保基础设施稳,再谈千万级调度。


















