Kafka时间轮学习总结

0 本文主要涉及

说明时间轮算法原理和优势,以及Kafka中改良版的时间轮

1时间轮算法说明

时间轮算法来源于 George Varghese 和 Tony Lauck 1996 年的论文 <Hashed and Hierarchical Timing Wheels: data structures to efficiently implement a timer facility>
时间轮算法是一种高效的定时任务管理算法(不涉及执行任务),任务增删查时间复杂度O(1),对比Java标准库Timer使用小顶堆实现,任务增删复杂度为O(logN)
原理:

时间轮就是如图所示的一种抽象数据结构,一个循环列表(circular buffer),每个列表中包含一个称之为槽(slot)
工作时图中的箭头按某一方向按固定频率轮动,每一次转动称为一个 tick,我们可以定义转一圈的的总 tick 数为ticksPerWheel,一个 tick 的持续时间为tickDuration*timeUnit(时间单位),以此来表示具体的时刻,而需要在某一时刻执行的任务通过连表方式存储在相应slot上(通过mod取余hash找到对应的slot),当指针转动到相应的slot时就去执行slot上的任务。
当时间跨度很大时,可以用多层时间轮来表示,或者也可以构造一个很大的时间轮

2Kafka中的时间轮

KafkaScheduler是Kafka的后台任务调度资源池,为LogManager、ReplicaManager和OffsetManager 等提供定时调度服务。
KafkaScheduler通过DelayedOperationPurgatory实现管理延迟操作,更底层则依赖于时间轮实现(像Kafka这种分布式系统的请求量巨大,性能要求也很高,JDK提供java.util.Timer和DelayedQueue底层实现使用的是堆这种数据结构,存取操作的复杂度都是O(nlog(n)),无法支持大量的定时任务,为了将定时任务的存取操作以及取消操作的时间复杂度降为O(1),一般会使用其他方式实现定时任务组件)
TimingWheel是一个存储定时任务的环形队列,底层使用数组实现,数组中的每个元素可以存放一个TimerTaskList对象。TimerTaskList是环形双向链表,在其中的链表项TimerTaskEntry中封装了真正的定时任务TimerTask。
TimerTaskList使用expiration 字段记录了整个TimerTaskList的超时时间。TimerTaskEntry中的expirationMs字段记录了超时时间戳,timerTask 字段指向了对应的TimerTask任务。
TimeTask中的delayMs记录了任务的延迟时间,timerTaskEntry字段记录了对应的TimerTaskEntry对象。
这三个对象是TimingWheel实现的基础。
TimingWheel提供了层级时间轮的概念,第一层时间轮的时间跨度比较小,而第二层时间轮的时间跨度比较大,以此类推。
TimeWheel中提供了add()、advanceClock()、addOverflowWheel()三个方法
add()方法实现了向时间轮中添加定时任务的功能
addOverflowWheel()方法会创建上层时间轮,默认情况下上层时间轮的tickMs是当前整个时间轮的时间跨度interval
advanceClock()方法会尝试推进当前时间轮的表针currentTime,同时也会尝试推进上层的时间轮的表针。随着当前时间轮的表针不断被推进,上层时间轮的表针也早晚会被推进成功
SystemTimer
SystemTimer是Kafka中的定时器实现,它在TimeWheel的基础上添加了执行到期任务、阻塞等待最近到期任务的功能。
SystemTimer.add()方法在添加过程中如果发现任务已经到期,则将任务提交到taskExecutor中执行;如果任务未到期,则调用TimeWheel.add()方法提交到时间轮中等待到期后执行
SystemTimer.advanceClock()方法完成了时间轮表针的推进,同时对到期的TimerTaskList中的任务进行处理。如果TimerTaskList到期,但是其中的某些任务未到期,会将未到期任务进行降级,添加到低层次的时间轮中继续等待;如果任务到期了,则提交到taskExecutor线程池中执行
DelayedOperation
DelayedOperation抽象类表示延迟操作,它对TimeTask进行了扩展,除了有定时执行的功能,还提供了检测其他执行条件的功能。我们可以认为DelayedOperation是一个延迟的、异步的操作。具体有四个实现类DelayedProduce,DelayedFetch,DelayedJoin ,DelayedHeartbeat,DelayedOperationPurgatory实际就是在管理这些DelayedOperation以及处理到期DelayedOperation。
总体结构如图:

实现上,Kafka的时间轮与普通的时间轮有所不同,Kafka的时间轮结构仅用于查询到期任务,时间的推进并不同于普通的时间轮实现按最小单位逐步推进完成,而是依赖于Java标准库中的DelayedQueue.poll()方法实现(通过小顶堆实现,获取并删除最近任务,时间复杂度为O(logN)),这样减少了无效的时间轮空转,不过额外增加了DelayedQueue中的堆结构需要维护(其中存放了TimerTaskList,由于时间轮中槽的个数是固定的,对应的TimerTaskList也只会往堆中添加一次,而添加具体任务操作是在TimerTaskList内,增加的额外操作可以接受)

参考博文:
Timing Wheel 定时轮算法 https://blog.csdn.net/mindfloating/article/details/8033340
惊艳的时间轮定时器 https://www.cnblogs.com/zhongwencool/p/timing_wheel.html
netty 源码解读之时间轮算法实现 - HashedWheelTimer https://zacard.net/2016/12/02/netty-hashedwheeltimer/
TimingWheel 本质与 DelayedOperationPurgatory 核心结构https://blog.csdn.net/chunlongyu/article/details/52971748
Kafka 解惑之时间轮(TimingWheel)https://blog.csdn.net/u013256816/article/details/80697456

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值