[算法数据结构专题]「延时队列算法」史上手把手教你针对层级时间轮(TimingWheel)实现延时队列的开发实战落地(上)

科技资讯 投稿 6600 0 评论

[算法数据结构专题]「延时队列算法」史上手把手教你针对层级时间轮(TimingWheel)实现延时队列的开发实战落地(上)

承接上文


前言回顾

什么是时间轮

    调度模型:时间轮是为解决高效调度任务而产生的调度模型/算法思想。
  • 数据结构:通常由hash表和双向链表实现的数据结构。

为什么用时间轮?

对比传统队列的优势

相比传统的队列形式的调度器来说,时间轮能够批量高效的管理各种延时任务、周期任务、通知任务等等。例如延时队列/延时任务体系

延时任务/队列体系

案例-Kafka的延时操作系列

比如,对于耗时的网络请求(比如Produce时等待ISR副本复制成功)会被封装成DelayOperation进行延迟处理操作,防止阻塞Kafka请求处理线程,从而影响效率和性能。

传统队列带来的性能问题

时间复杂度上这两者插入和删除操作都是 O(logn,不能满足Kafka的高性能要求。

基于JDK自带的Timer+DelayQueue实现

ScheduledThreadPoolExecutor是JDK的定时任务实现的一种方式,其实也就是DelayQueue+池化线程的一个实现

基于时间轮TimeWheel的实现

当流量小时,使用DelayQueue效率更高。当流量大事,使用时间轮将大大提高效率。

时间轮算法是怎么样的,算法思想是什么?

时间轮的数据结构

    时间轮(TimingWheel) 是一个存储定时任务的环形队列(cycle array),底层采用环形数组实现,数组中的每个元素可以对应一个时间轮任务任务列表(TimeWheelTaskList)

  • 时间轮任务任务列表(TimeWheelTaskList) 是一个环形的双向链表,其中的每个元素都是延时/定时任务项(TaskEntry),其中封装了任务基本信息和元数据(Metadata)。

    startMs: 开始时间

  • 时间轮执行的最小单位。时间轮由多个时间格组成,每个时间格代表当前时间轮的基本时间跨度就是tickMs。

  • 时间轮中环形队列的数量。时间轮的时间格数量是固定的,可用wheelSize来表示。

  • 时间轮的整体时间跨度 = tickMs * wheelSize

tickMs=1ms,wheelSize=20,那么可以计算得出interval为20ms

currentTime游标指针

整个时间轮的总体跨度是不变的,随着指针currentTime的不断流动,当前时间轮所能处理的时间段也在不断后移,整个时间轮的时间范围在currentTime和currentTime+interval之间。

currentTime游标指针的运作流程

    初始情况下表盘指针currentTime指向时间格0,此时有一个定时为2ms的任务插入进来会存放到时间格为2的任务列表中。

  1. 此时若又有一个定时为8ms的任务插入进来,则会存放到时间格10中,currentTime再过8ms后会指向时间格10。

总之,整个时间轮的总体跨度是不变的,随着指针currentTime的不断推进,当前时间轮所能处理的时间段也在不断后移,总体时间范围在currentTime和currentTime+interval之间。

层次化时间轮机制

层次化时间轮实现原理介绍

层次化时间轮任务升级跃迁

    第一层的时间轮tickMs=1ms, wheelSize=20, interval=20ms

第一层和第二层时间轮的wheelSize是固定的,都是20,那么第二层的时间轮的总体时间跨度interval为400ms。正好是第一层时间轮的20倍。以此类推,这个400ms也是第三层的tickMs的大小,第三层的时间轮的总体时间跨度为8000ms

    第N层时间轮走了一圈,等于N+1层时间轮走一格。即高一层时间轮的时间跨度等于当前时间轮的整体跨度。

层次化时间轮任务降级跃迁

案例介绍

层次化时间轮任务升级跃迁

例如:350ms的定时任务,显然第一层时间轮不能满足条件,所以就升级到第二层时间轮中,最终被插入到第二层时间轮中时间格17所对应的TimeWheelTaskList中。如果此时又有一个定时为450ms的任务,那么显然第二层时间轮也无法满足条件,所以又升级到第三层时间轮中,最终被插入到第三层时间轮中时间格1的TimeWheelTaskList中。

层次化时间轮任务降级跃迁

随着时间的流逝,当次TimeWheelTaskList到期之时,原本定时为450ms的任务还剩下50ms的时间,还不能执行这个任务的到期操作。

再经历了40ms之后,此时这个任务又被“察觉”到,不过还剩余10ms,还是不能立即执行到期操作。所以还要再有一次时间轮的降级,此任务被添加到第一层时间轮到期时间为[10ms,11ms的时间格中,之后再经历10ms后,此任务真正到期,最终执行相应的到期操作。

后续章节预告

接下来小编会出【算法数据结构专题】「延时队列算法」史上手把手教你针对层级时间轮(TimingWheel)实现延时队列的开发实战落地(下),进行实战编码进行开发对应的层次化的时间轮算法落地。

编程笔记 » [算法数据结构专题]「延时队列算法」史上手把手教你针对层级时间轮(TimingWheel)实现延时队列的开发实战落地(上)

赞同 (31) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽