【摘要】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 的插入和弹出操作开销也更小
点击关注,第一工夫理解华为云陈腐技术~