✅什么是时间轮?

一、问题解析

时间轮算法(Time Wheel Algorithm)是一种用于处理定时任务和调度的常见算法。

时间轮算法主要需要定义一个时间轮盘,在一个时间轮盘中划分出多个槽位,每个槽位表示一个时间段,这个段可以是秒级、分钟级、小时级等等。如以下就是把一个时间轮分为了60个时间槽,每一个槽代表一秒钟。

image.png



然后当我们有定时任务需要执行的时候,就把他们挂在到这些槽位中,这个任务将要在哪个槽位中执行,就把他挂在到哪个槽位的链表上。

比如当前如果是0秒,那么要3秒后执行,那就挂在槽位为3的那个位置上。

 

image.png



而随着时间的推移,轮盘不断旋转,任务会被定期触发。

因为这个时间轮是60个槽位,那么他就会在一分钟完整的转完一圈,那么就有一个指针,每一秒钟在槽位中进行一次移动。这个操作是有一个单独的线程来做的,他的工作就是每一秒钟改变一次current指针。

image.png



然后还有一个线程池,在指针轮转到某个槽位上的时候,在线程池中执行链表中需要执行的任务。

以上就是一个简单的时间轮算法,但是这个时间轮存在一个问题,那就是我们把它分了60个槽,那么就意味着我们的定时任务最多只支持60s以内的。

那么,怎么解决这个问题呢?

首先能想到的最简单的方式就是加槽位,比如我要支持5分钟的延迟任务,那么就可以把槽位设置为300个。

还有就是也可以调整时间轮槽位移动的延迟,比如把1秒钟移动一次,改为1分钟移动一次,那么就可以支撑60分钟的延迟任务了。

但是这两个办法都不够灵活,而且是有瓶颈的。于是有一种新的办法。

round

在时间轮中增加一个round的标识,标识运行的圈数,比如说上面的60s的时间轮,如果我要200s之后运行,那么我在设置这个任务的时候,就把他的round设置为 200/60 = 3 ,然后再把它放到 200%60 = 20的这个槽位上。

image.png



有了这个round之后,每一次current移动到某个槽位时,检查任务的round是不是为0,如果不为0,则减一。

image.png



这样时间轮转到第三圈时,round的值会变成0,再第四圈运行到current=20的时候,发现round=0了,那么就可以执行这个任务了。

这样就解决了我们前面说的问题了。

但是这个方案还存在一个问题,那就是这个round的检查过程,需要把所有任务都遍历一遍,效率还是没那么高。

分层时间轮

为了解决遍历所有任务的问题,我们可以引入分层时间轮。我们在刚刚的秒级时间轮的基础上,在定义一个分钟级时间轮

image.png



也就是说我们对于200s以后执行这个任务,我们先把他放到分钟级时间轮上,这个时间轮的槽位每一分钟移动一次,当移动时候,发现某个槽位上有这一分钟内需要执行的任务时。

把这个任务取出来,放到秒级时间轮中。这样在第3分20秒的时候,就可以运行这个任务了。

这就是分层时间轮。在分层时间轮包括多个级别的时间轮,每个级别的时间轮都有不同的粒度和周期。

通常,粒度较细的时间轮拥有更短的周期,而粒度较粗的时间轮拥有更长的周期。例如,分层时间轮可以包括毫秒级、秒级、分钟级等不同粒度的时间轮。

当一个任务需要被调度时,它被分配到适当级别的时间轮中,每个级别的时间轮都独立地旋转。当一个时间轮的指针到达某个位置时,它将触发执行该级别时间轮中的任务。如果某个任务在较粗的时间轮中已经到期,它将被升级到下一级时间轮。

当任务升级到下一级时间轮时,任务的调度粒度变得更细。这意味着任务将在更短的时间内被触发,从而更精确地满足其调度要求。


扩展知识

典型应用

时间轮算法在各种框架和库中都有广泛的应用。以下是一些应用时间轮算法的常见框架和库:

1Netty:Netty 是一款高性能的网络通信框架,它使用时间轮算法来处理定时任务和超时检测。时间轮用于管理通道的超时和重连机制。
2Akka:Akka 是一个并发编程框架,它包括一个调度器,该调度器使用时间轮算法来管理和触发并发任务。这使得 Akka 能够支持高并发和复杂的任务调度需求。
3Kafka:Apache Kafka 是一个分布式消息队列系统,它使用时间轮算法来管理消息的过期和删除。时间轮用于清理过期消息,以释放存储空间。
4Hystrix:Hystrix 是 Netflix 开发的容错和延迟容忍库,它使用时间轮来管理命令执行和熔断状态的转换。
5Disruptor:Disruptor 是一个高性能并发框架,它使用时间轮算法来管理任务的并发执行,以提高处理大量事件的性能。
6xxl-job:在以前的版本的xxl-job中,使用quartz做定时任务调度,但是在7.28版本中去除了quartz,改用了时间轮算法。

9,代码优化,CONCURENTHASHMAP变量类型改为CONCURRENTMAP,避免因不同版本实现不同导致的兼容性问题;

12,项目依赖升级至较新稳定版本,如SPRING,SPRINGBOOT,GROOY,X-RPC等等;并清理冗余POM;

,权限管理:执行器维度进行权限控制,管理员拥有全量权限,普通用户需要分配执行器权限后才允许相关操

13,升级X-RPC至较新版本,修复代理服务初始化时远程服务不可用导致长连几余创建的问题;

,任务日志主键调整为LONG数据类型,防止海量日志情况下数据溢出;

底层线程模型重构:移除QUARTZ线程池,降低系统线程与内存开销

7.27版本V2.1.0RELEASENOTES[2019-07-07]

16,调度组件销毁流程优化,先停止调度线程,然后等待时间轮内存量任务处理完成,最终销时间轮线程;

,用户管理:支持在线管理系统用户,存在管理员,普通用户两种角色;

,自研调度组件,移除QUAZ依赖:一方面是为了精简系统降低几余依赖,另一方面是为了提供系统的可控度与稳定性;

8,HTTPJOBHANDLER优化,响应数据指定UTF-8格式,避免中文乱码;

调度:集群竞争,负载方式协同处理,锁竞争-更新触发信息-推送时间轮锁释放-锁竞争;

,任务列表优化,支持根据"任务状态","负责人"属性筛选任务

,底层表结构重构:移除11张QUARTZ相关表,并对现有表结构优化梳理;

14,首页调度报表的日期排序在TIDB下乱序问题修复;

7,执行器回调线程优化,回调地址为空时销毁问题修复;

5,调度中心与执行器双向通讯超时时间调整为3S;

11,任务日志列表交互优化,操作按钮合并为分割按钮;

触发:单节点周期性触发,运行事件如DELAYQUEUE;

9,新增BOOT执行器SAMPLE示例项目

,注册表索引优化,缓解锁

,调度线程池参数调优;

image.png

二、粉丝福利

我是浮生,一个工作十四年经验的Java程序员!

最近很多同学问我有没有java学习资料,我根据我从小白到架构师多年的学习经验整理出来了一份80W字面试解析文档、简历模板、学习路线图、java必看学习书籍 、 需要的小伙伴 可以关注我
公众号:“ 
灰灰聊架构 ”, 回复暗号:“ 321 ”即可获取

 

  • 18
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值