1.背景
RocketMQ支持延时消息,但是只支持提前定义好的16个时间区间,为了满足业务上的任意时间的需求,需要对RocketMQ进行升级改造。本着从简到难的处理方式,分三大块完成这个系列。
- xxl-job调度是怎么实现的
- 时间轮算法介绍
- RocketMQ延迟消息的实现
- RocketMQ自定义延时消息改造过程
本文重点是针对xxl的获取任务展开,没有涉及到具体的执行流程,具体的执行流程在以后的文章中进行扩展。
2.流程
2.1 入时间轮阶段
【流程描述】
- 查询列表表中下次执行时间小于等于 当前时间+5S的所有任务列表
- 此时查询出来的列表数据中分成三种情况
- 5S之前的数据直接的丢弃并且刷新下次的执行时间。
- 立即需要执行的任务,并且刷新下次执行时间,判断下次执行的时间在未来的5S内,加入到时间轮。
- 未来5S的数据加入到时间轮。
- ringData的key是执行时间在当前分钟的第几秒 ,value是对应的任务的ID
2.2 出时间轮阶段
【流程描述】
while循环从第一步的Map中读取符合当前秒数以及上一秒的数据,提交执行任务。
int nowSecond = Calendar.getInstance().get(Calendar.SECOND);
【tips】
返回的秒的区间范围是0~59
获取上一秒数据的时候如果是0,从Map中取得值为-1,获取不到数据,从而获取到的上一秒数据为null,会出现上一秒数据没被执行的情况。
处理的代码如下:
for (int i = 0; i < 2; i++) {
// nowSecond取值0-59
//当nowSecond=0&&i=1,此时remove的值之后为null
// 不能执行前一秒的数据
List<Integer> tmpData = ringData.remove( (nowSecond+60-i)%60 );
if (tmpData != null) {
ringItemData.addAll(tmpData);
}
}
3.总结
- xxl的时间轮相对来说比较简答,直接通过java中的Map来实现,没有定义真正时间轮算法中的指针,轮盘等概念。
- 在整个的设计上有一些细化的点没有指出来,比如处理任务的 "快慢线程池"的概念。以及从这个概念引出的获取待放入到时间轮中数据多少。
- 具体的类可以参考 JobScheduleHelper。