时间轮系列-xxl的实现

244 阅读2分钟

1.背景

RocketMQ支持延时消息,但是只支持提前定义好的16个时间区间,为了满足业务上的任意时间的需求,需要对RocketMQ进行升级改造。本着从简到难的处理方式,分三大块完成这个系列。

  • xxl-job调度是怎么实现的
  • 时间轮算法介绍
  • RocketMQ延迟消息的实现
  • RocketMQ自定义延时消息改造过程

本文重点是针对xxl的获取任务展开,没有涉及到具体的执行流程,具体的执行流程在以后的文章中进行扩展。

2.流程

2.1 入时间轮阶段

image.png

【流程描述】

  1. 查询列表表中下次执行时间小于等于 当前时间+5S的所有任务列表
  2. 此时查询出来的列表数据中分成三种情况
  3. 5S之前的数据直接的丢弃并且刷新下次的执行时间。
  4. 立即需要执行的任务,并且刷新下次执行时间,判断下次执行的时间在未来的5S内,加入到时间轮。
  5. 未来5S的数据加入到时间轮。
  6. ringData的key是执行时间在当前分钟的第几秒 ,value是对应的任务的ID

2.2 出时间轮阶段

时间轮系列-xxl的实现

【流程描述】

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.总结

  1. xxl的时间轮相对来说比较简答,直接通过java中的Map来实现,没有定义真正时间轮算法中的指针,轮盘等概念。
  2. 在整个的设计上有一些细化的点没有指出来,比如处理任务的 "快慢线程池"的概念。以及从这个概念引出的获取待放入到时间轮中数据多少。
  3. 具体的类可以参考 JobScheduleHelper。