Kafka延迟任务时间轮解析 + java版源码

1. 单层时间轮

想象现在有个时钟,指针每1s移动一次。转完一圈需要20s

0时刻提交一个任务,希望3s后执行

可以看到该任务将会被放到 index = (3 / 1 ) % 20 = 3 的位置上,1代表着时间轮每个节点的时间长度为 1s,20代表时间轮的节点个数。

currentTime来到3,time = 3 的任务开始执行

其中绿色的节点表示可以重复使用,这个怎么理解呢?(当0时刻的时候,单层时间轮支持添加的任务延时范围为(0-19s),当时间来到3s,那么他支持的时间范围就是(3-22),也就是 time = 20的任务被添加到节点0,time = 21的节点被添加到 节点1, time = 22的节点被添加到节点2

currentTime 来到 3,添加 time = 20 的任务

可以看到该任务将会被放到 index = (20 / 1 ) % 20 = 0 的位置上,1代表着时间轮每个节点的时间长度为 1s,20代表时间轮的节点个数。

currentTime 来到 20, time = 20 的任务开始执行

总结:

假设现在的时间是 currentTime, 每个节点的时间间隔是1s, 节点个数是 20 个

  1. 如果添加的任务time >= (currentTime + 20 * 1) 那么该任务不能被添加(会触发时间轮升级)。
  2. 如果添加的任务time < currentTime + 1,那么该任务应该立即被执行。
  3. 添加的任务 time 合法, 那么他会被添加到索引 (time / 1) % 20 的位置。

2. 时间轮升级和降级

currentTime = 0 时刻,添加 延迟任务在 20s 执行。

我们会发现,如果当前时间轮不能添加这种超过自身支持范围的延迟任务,那么会创建一个新的时间轮,新的时间轮的单个节点时间跨度是当前时间轮的总支持时间,也就是新的时间轮单个节点跨度20s,当前时间轮单个节点跨度1s。 同时当前时间轮转动一圈,新的时间轮推动一个节点。

currentTime = 0 时刻,添加 延迟任务在 35s 执行。

currentTime = 20 时刻。

currentTime = 20的时候,内层时间轮刚好走完一圈,所以外层时间轮刚好跨过一个节点。

那么此时会触发时间轮降级,也就是说外层时间轮的节点会降级到下一层时间轮。

时间轮降级

time = 20 的任务因为 (time < currentTime + 1) 那么会立即执行。

time = 35 的任务会被放到内层时间轮 15号节点

currentTime = 35, time = 35的任务执行

总结

通过时间轮升级和降级,就可以支持任意时长的延时任务了。

添加元素优先从内层时间轮开始添加,如果不能添加进去,那么添加到外层时间轮。 当时间来到外层时间轮有任务的节点,就会触发时间轮降级。其实从抽象的角度上来说,就是将延迟执行时间更加精细化。举个例子,如果外层时间轮代表小时,那么外层时间轮的一个节点的任务可能是 (1小时10分钟,1小时20分钟执行),那么需要把他降级到内存时间轮。也就是降级为 10分钟,和20分钟,让粒度更小,最终降级到最内层时间轮(时间粒度最细,此时走到哪个节点就直接触发执行了。)

3. cpu空转问题

剩下的一个问题就是如何推动时钟运行?

这里可以采用一种很巧妙的设计,可以把所有添加到时间轮的任务同时塞到 java 的 DelayQueue里面,也就是构建成一个小根堆,堆顶的任务一定是最先执行的。

然后开一个线程,阻塞获取小根堆堆顶元素。获得之后丢给线程池异步执行延迟任务。这样即使时间轮里面没有任何任务,消费者线程会被阻塞,不会造成cpu空转。

任务消费线程伪代码

java 复制代码
while (true) {
   // 阻塞获得最开始执行的任务
   Task task = minHeap.take();
   // 异步消费任务
   executor.submit(()->{
       task.run();
   });
}

4. 源码

上面就是kafka实现的时间轮原理,由于kafka server端采用的是 Scala,所以这里提供java版本实现的时间轮算法。

TimingWheel-Kafka: TimingWheel-Kafka (gitee.com)

相关推荐
假装我不帅23 分钟前
asp.net framework从webform开始创建mvc项目
后端·asp.net·mvc
神仙别闹26 分钟前
基于ASP.NET+SQL Server实现简单小说网站(包括PC版本和移动版本)
后端·asp.net
计算机-秋大田1 小时前
基于Spring Boot的船舶监造系统的设计与实现,LW+源码+讲解
java·论文阅读·spring boot·后端·vue
货拉拉技术1 小时前
货拉拉-实时对账系统(算盘平台)
后端
掘金酱2 小时前
✍【瓜分额外奖金】11月金石计划附加挑战赛-活动命题发布
人工智能·后端
代码之光_19802 小时前
保障性住房管理:SpringBoot技术优势分析
java·spring boot·后端
ajsbxi2 小时前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
颜淡慕潇3 小时前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决
尘浮生4 小时前
Java项目实战II基于Spring Boot的光影视频平台(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·后端·maven·intellij-idea
尚学教辅学习资料4 小时前
基于SpringBoot的医药管理系统+LW示例参考
java·spring boot·后端·java毕业设计·医药管理