一、xxl-job架构图
1、调度中心
负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码。调度系统与任务解耦,提高了系统可用性和稳定性,同时调度系统性能不再受限于任务模块。
2、执行器
负责接收调度请求并执行任务逻辑。任务模块专注于任务的执行等操作,开发和维护更加简单和高效;
接收“调度中心”的执行请求、终止请求和日志请求等。
二、执行器注册流程
1、调度中心注册(注册/删除)异步处理
线程池配置:2核心线程数,最大线程数10,任务队列2000,活跃时间30s,执行+日志的拒绝策略。
2、注册数据处理流程
三、调度中心触发任务
1、任务触发快慢线程池设计
快线程池配置:10核心线程数,最大线程数至少200,任务队列1000
慢线程池配置:10核心线程数,最大线程数至少100,任务队列2000
2、job降级逻辑
job超时次数超过500ms为超时,一分钟内任务超时次数超过10次(不包含10),运行触发任务有快线程池fastTriggerPool降级为慢线程池slowTriggerPool
3、触发启动加排他锁
为什么要控制? 因为触发中心是集群部署,每个实例都会执行触发任务。需要控制在某一时刻只有一个实例在触发任务。
4、时间轮
ringData, Map<秒数, List>
//存数
int ringSecond = (int)((jobInfo.getTriggerNextTime()/1000)%60);
ringItemData.add(jobId);
//取数
int nowSecond = Calendar.getInstance().get(Calendar.SECOND);
for (int i = 0; i < 2; i++) {
List<Integer> tmpData = ringData.remove( (nowSecond+60-i)%60 );
if (tmpData != null) {
ringItemData.addAll(tmpData);
}
}
job超时统计
long minTim_now = System.currentTimeMillis()/60000;
if (minTim != minTim_now) {
minTim = minTim_now;
jobTimeoutCountMap.clear();
}
5、触发job预读5s数据
预读数量计算:(快线程大小 + 慢线程池大小) * 20 默认:(200 + 100)* 20 = 6000
预读时间:5秒。 运行中的Job
6、ringData读取逻辑
下一秒开始 TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis() % 1000);
获取当前秒和过去1秒的任务。ringData删除掉已经触发的任务。
7、添加触发任务流程
1、快慢线程池设计,降级处理,防止正常触发的任务被慢job阻塞。
2、ConcurrentMap存储超时次数,在多线程场景下的使用。
3、job超时统计数据保存时效逻辑
long minTim_now = System.currentTimeMillis()/60000;
if (minTim != minTim_now) {
minTim = minTim_now;
jobTimeoutCountMap.clear();
}
8、调度中心触发job-路由策略
四、任务执行
五、任务回调
注册中心回调线程池callbackThreadPool:2核心线程数,最大线程数20,任务队列3000,活跃时间30s,执行+日志的拒绝策
job处理成功处理,主要是触发子任务,多个子任务配置用逗号分割,逐个触发子任务。
更新job日志信息,增加触发子任务的信息,日志截取避免超过text类型大小(64kb)。
失败job处理流程(monitorThread)
六、设计的细节点。
1、国际化设计
支持 zh_CN:中文简体, zh_TC:中文繁体, en:英文
默认是zh_CN. 通过配置xxl.job.i18n可以设置。
根据不同的语言选择,加载不同的国际化文件
message_zh_CN.properties,
message_zh_TC.properties,
message_en.properties
将系统内的语言修改成对应的语言。
2、job调用统计
按天统计,统计近3天的数据。1分钟更新log-report表
log日志清理逻辑。 job-log最少保存7天。一天清理一次log。
3、InheritableThreadLocal的使用
InheritableThreadLocal主要用于子线程创建时,需要自动继承父线程的ThreadLocal变量,方便必要信息的进一步传递。
在维持Jobcontext的时候就使用了InheritableThreadLocal,方便子线程使用。
4、LinkedBlockingQueue take和poll的巧妙应用
take方法会一直阻塞,poll允许继续执行。在执行job时候就使用的poll,以便于统计空转的次数,超过30次,kill掉线程,以释放无用的线程占用内存空间。