【摘要】 Kafka工夫轮是Kafka实现高效的延时工作的根底,它模仿了现实生活中的钟表对工夫的示意形式,同时,工夫轮的形式并不仅限于Kafka,它是一种通用的工夫示意形式,本文次要介绍Kafka中的工夫轮原理。
Kafka中存在一些定时工作(DelayedOperation),如DelayedFetch、DelayedProduce、DelayedHeartbeat等,在Kafka中,定时工作的增加、轮转、执行、沦亡等是通过工夫轮来实现的。(工夫轮并不是Kafka独有的设计,而是一种通用的实现形式,Netty中也有用到工夫轮的形式)
1. 工夫轮是什么
参考网上的两张图(摘自 https://blog.csdn.net/u013256…)
这两张图就比较清楚的阐明了Kafka工夫轮的构造了:相似事实中的钟表,由多个环形数组组成,每个环形数组蕴含20个工夫单位,示意一个工夫维度(一轮),如:第一层工夫轮,数组中的每个元素代表1ms,一圈就是20ms,当延迟时间大于20ms时,就“进位”到第二层工夫轮,第二层中,每“一格”示意20ms,依此类推…
对于一个提早工作,大体蕴含三个过程:进入工夫轮、降级和到期执行。
进入工夫轮
依据延迟时间计算对应的工夫轮“档次”(如钟表中的“小时级”还是“分钟级”还是“秒级”,实际上是一个一直“降级”的过程,直到找到适合的“档次”)
计算在该轮中的地位,并插入该地位(每个bucket是一个双向链表,可能蕴含多个提早工作,这也是工夫轮提高效率的一大起因,前面会提到)
若该bucket是首次插入,须要将该bucket退出DelayQueue中(DelayQueue的引入是为了解决“空推动”,前面会提到)
降级
当工夫“推动”到某个bucket时,阐明该bucket中的工作在以后工夫轮中的工夫曾经走完,须要进行“降级”,即进入更小粒度的工夫轮中,reinsert的过程和进入工夫轮是相似的
到期执行
在reinsert的过程中,若发现曾经到期,则执行这些工作
整体过程大抵如下:
2. 工夫的“推动”
一种直观的想法是,像事实中的钟表一样,“一格一格”地走,这样就须要有一个线程始终不停的执行,而大多数状况下,工夫轮中的bucket大部分是空的,指针的“推动”就没有本质作用,因而,为了缩小这种“空推动”,Kafka引入了DelayQueue,以bucket为单位入队,每当有bucket到期,即queue.poll能拿到后果时,才进行工夫的“推动”,缩小了 ExpiredOperationReaper 线程空转的开销。
3. 为什么要用工夫轮
用到提早工作时,比拟间接的想法是DelayQueue、ScheduledThreadPoolExecutor 这些,而工夫轮相比之下,最大的劣势是在工夫复杂度上:
工夫复杂度比照:
因而,实践上,当工作较多时,TimingWheel的工夫性能劣势会更显著
总结一下Kafka工夫轮性能高的几个次要起因:
(1)工夫轮的构造+双向列表bucket,使得插入操作能够达到O(1)的工夫复杂度
(2)Bucket的设计让多个工作“合并”,使得同一个bucket的屡次插入只须要在delayQueue中入队一次,同时缩小了delayQueue中元素数量,堆的深度也减小,delayqueue的插入和弹出操作开销也更小
点击关注,第一工夫理解华为云陈腐技术~