TFdream / blog

个人技术博客,博文写在 Issues 里。
Apache License 2.0
129 stars 18 forks source link

时间轮(Timing Wheel)实践 #318

Open TFdream opened 3 years ago

TFdream commented 3 years ago

时间轮是一个应用场景很广的组件,在很多高性能中间件中都有它的身影,如Netty、Quartz、Akka,当然也包括Kafka,本文主要介绍时间轮在kafka的应用和实战,从核心源码和设计的角度对时间轮进行深入的讲解 。

案例

从2个面试题说起,第一个问题:如果一台机器上有10w个定时任务,如何做到高效触发?

具体场景是:

有一个APP实时消息通道系统,对每个用户会维护一个APP到服务器的TCP连接,用来实时收发消息,对这个TCP连接,有这样一个需求:“如果连续30s没有请求包(例如登录,消息,keepalive包),服务端就要将这个用户的状态置为离线”。
其中,单机TCP同时在线量约在10w级别,keepalive请求包较分散大概30s一次,吞吐量约在3000qps。

解决方案

延迟操作,通常可以采用两个方案:

  1. Timer:定时器维护一个优先队列,到时间点执行,Java中可以使用JDK自带的Timer或者DelayQueue来实现延迟的功能,插入和删除操作的平均时间复杂度为O(nlog(n));
  2. 时间轮(timingWheel ),维护一个存放任务组的数组,每一个槽都维护一个存储 task 的双向链表。开始执行时,计时器每隔指定时间执行一个槽里面的 tasks。

方案 2 把维护 task 从 优先队列 O(nlog(n)) 降到 双向链表 O(1),而执行 task 也只要轮询一个时间点的 tasks O(N),不需要像优先队列,放入和删除元素 O(nlog(n))。

相关资料