Kafka作为实时消息队列的一个重要框架,在大数据技术架构搭建层面,越来越得到重用。相应的,Kafka在大数据技术生态当中的地位,也越来越重要。今天的大数据开发学习分享,我们就来讲讲Kafka延迟队列的部分。
kafka基于时间轮(TimingWheel)自定义了一个用于实现延迟功能的定时器。
时间轮是一个存储定时任务的环形队列,底层采用数组实现,数组中的每个元素可以存放一个定时任务列表(TimerTaskList)。TimerTaskList是一个环形的双向链表,链表中的每一项表示的都是定时任务项(TimerTaskEntry),其中封装了真正的定时任务TimerTask。
时间轮由多个时间格组成,可以想象成时钟。
tickMs:每个时间格代表当前时间轮的基本时间跨度
wheelSize:时间轮的时间格个数是固定的,可用wheelSize来表示
所以整体时间轮的时间跨度interval=tickMs*wheelSize
currentTime:时间轮还有一个表盘指针,用来表示时间轮当前所处的时间,currentTime是tickMs的整数倍。
举个栗子:
tickMs=1ms,wheelSize=20,那么interval=1*20=20ms
初始情况下currentTime指向0时间格。此时一个定时为2ms的任务插入进来会存放到时间格为2的TimerTaskList中。
随着currentTime指针随着时间不断推进,当currentTime指向2时间格时,就需要将时间格2所对应的TimeTaskList中的任务做相应的到期操作。
此时若又有一个定时为8ms的任务插入进来,则会存放到时间格10中,currentTime再过8ms后会指向时间格10。
同时一个19ms的任务插入进来,会存放到时间格1中。
如果有一个定时任务的时间大于interval怎么办?
直接扩充wheelSize的大小?这个是没底线的,定时任务时间不知道会有多大。而且如果wheelSize很大,不仅占用很大的内存空间,而且效率也会拉低。
Kafka为此引入了层级时间轮的概念,当任务的到期时间超过了当前时间轮所表示的时间范围时,就会尝试添加到上层时间轮中。
第一层的时间轮interval=20ms,那么第二层的时间轮的tickMs=20ms。每一层的wheelSize是相同的额,所以第二层的时间跨度interval=20*20=400ms。同理,第三层时间轮的interval=400*20=8000ms。
如果有一个350ms的定时任务,第一层时间轮无法满足,就升级到第二层时间轮中,最终被插入到第二层时间轮中时间格17所对应的TimerTaskList中。其他层级同理,如一个450ms的定时任务会放在第三层的第一格中。
以450ms的定时任务为例,当第三层的currentTime指向时间格1时,此时450ms的定时任务还剩下50ms,会有一个时间轮降级操作。此时第一层时间轮的总体时间跨度不够,而第二层足够,所以该任务被放到第二层时间轮到期时间为[40ms,60ms)的时间格中。再经历40ms后,任务还剩下10ms,会再次降级放到到第一层时间轮[10ms,11ms)的时间格中。之后再经历10ms,此任务真正到期,最终执行相应的到期操作。
总的来说,延迟队列是Kafka当中的一个重要功能点,对于大数据背景下的实时消息队列的处理,有重要的作用。