时间轮队列php,一张图理解Kafka时间轮(TimingWheel),看不懂算我输!

如图就是一个简单的时间轮:

5944491a2bb995a24e49e9e61aa9a1c2.png

图中大圆的圆心位置表示的是当前的时间,随着时间推移, 圆心处的时间也会不断跳动。

下面我们对着这个图,来说说Kafka的时间轮TimingWheel。

Kafka时间轮的底层就是一个环形数组,而数组中每个元素都存放一个双向链表TimerTaskList,链表中封装了很多延时任务。

Kafka中一个时间轮TimingWheel是由20个时间格组成,wheelSize = 20;每格的时间跨度是1ms,tickMs = 1ms。参照Kafka,上图中也用了20个灰边小圆表示时间格,为了动画演示可以看得清楚,我们这里每个小圆的时间跨度是1s。

所以现在整个时间轮的时间跨度就是 tickMs * wheelSize ,也就是 20s。从0s到19s,我们都分别有一个灰边小圆来承载。

Kafka的时间轮还有一个表盘指针 currentTime,表示时间轮当前所处的时间。也就是图中用黑色粗线表示的圆,随着时间推移, 这个指针也会不断前进;

24203a56e74b7dd728c183783a7758c2.png

添加定时任务

有了时间轮,现在可以往里面添加定时任务了。我们用一个粉红色的小圆来表示一个定时任务。

7b78194a1753e842d2fd80e2cd91dcfa.png

这里先讲一下设定,每一个定时任务都有延时时间delayTime,和过期时间ExpiredTime。

比如当前时间是10s,我们添加了个延时时间为2s的任务,那么这个任务的过期时间就是12s,也就是当前时间10s再走两秒,变成了12s的时候,就到了触发这个定时任务的时间。

而时间轮上代表时间格的灰边小圆上显示的数字,可以理解为任务的过期时间。

be031b203d95d1d8c1554d5febf41480.png

讲清楚这些设定后,我们就开始添加定时任务吧。

初始的时候, 时间轮的指针定格在0。此时添加一个超时时间为2s的任务, 那么这个任务将会插入到第二个时间格中。

58ba0739ffcf829d3c680caf89eae24a.png

当时间轮的指针到达第二个时间格时, 会处理该时间格上对应的任务。在动画上就是让红色的小圆消失!

da3f16d8d637377096153e4d541d4978.png

如果这个时候又插入一个延时时间为8s的任务进来, 这个任务的过期时间就是在当前时间2s的基础上加8s, 也就是10s, 那么这个任务将会插入到过期时间为10s的时间格中。

925ba971e54336c051a706534bf50289.png

2 "动态"时间轮

到目前为止,一切都很好理解。

那么如果在当前时间是2s的时候, 插入一个延时时间为19s的任务时, 这个任务的过期时间就是在当前时间2s的基础上加19s, 也就是21s。

请看下图,当前的时间轮是没有过期时间为21s的时间格。这个任务将会插入到过期时间为1s的时间格中,这是怎么回事呢?

9c6165b4285e2d863ac77fdddea8bd62.png

复用时间格

为了解答上面的问题,我们先来点魔法, 让时间轮上的时间都动起来!

690e2362c89db8dcac6a6c7249165c80.png

其实呢,当指针定格在2s的位置时, 时间格0s, 1s和2s就已经是过期的时间格。

也就是说指针可以用来划分过期的时间格[0,2]和未来的时间格 [3,19]。而过期的时间格可以继续复用。比如过期的时间格0s就变成了20s, 存放过期时间为20s的任务。

理解了时间格的复用之后,再看回刚刚的例子,当前时间是2s时,添加延时时间为19s的任务,那么这个任务就会插入到过期时间为21s的时间格中。

ae6a228a060ddf8904976899cdeb73a5.png

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用Spring Boot来整合Kafka时间来实现延时处理。下面是一个简单的示例: 首先,确保你已经在Spring Boot项目中添加了Kafka的依赖。可以在pom.xml文件中添加如下依赖: ```xml <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency> ``` 接下来,创建一个Kafka生产者来发送延时消息。你可以使用`KafkaTemplate`来发送消息。这是一个简单的示例: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Component; @Component public class KafkaProducer { @Autowired private KafkaTemplate<String, String> kafkaTemplate; public void sendDelayedMessage(String topic, String message, long delay) { kafkaTemplate.send(topic, message).get(delay, TimeUnit.MILLISECONDS); } } ``` 在这个示例中,`sendDelayedMessage`方法接受一个`topic`、消息内容`message`和延时时间`delay`(以毫秒为单位)。它使用`KafkaTemplate`发送消息,并设置了延时时间。 接下来,创建一个Kafka消费者来处理延时消息。你可以使用`@KafkaListener`注解来监听指定的topic并处理消息。这是一个简单的示例: ```java import org.springframework.kafka.annotation.KafkaListener; import org.springframework.stereotype.Component; @Component public class KafkaConsumer { @KafkaListener(topics = "your-topic") public void receiveMessage(String message) { // 处理收到的消息 System.out.println("Received message: " + message); } } ``` 在这个示例中,`receiveMessage`方法使用`@KafkaListener`注解来监听名为"your-topic"的Kafka主题,并在收到消息时进行处理。 最后,你可以在需要发送延时消息的地方调用`KafkaProducer`的`sendDelayedMessage`方法,将延时消息发送到Kafka中。 注意:这只是一个简单的示例,实际应用中可能需要更复杂的逻辑来处理延时消息。你可能需要使用时间法来管理延时消息的触发和删除。你可以在项目中引入第三方库来实现时间的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值