• 胡夕
    置顶
    2020-06-15
    你好,我是胡夕。我来公布上节课的“课后讨论”题答案啦~ 上节课,咱们结合源码重点了解了PartitionStateMachine的原理。课后我让你去自行分析下triggerOnlineStateChangeForPartitions方法,并尝试找出它被调用的时机。其实,这个方法,顾名思义就是将一组给定的主题分区的状态变更到Online状态。在执行变更前,必须要判断这些分区所属的主题当前没有被执行删除操作。另外除了要变更状态之外,该方法还会为这些分区执行Leader选举。triggerOnlineStateChangeForPartitions方法被调用的时机主要有3个:1. 选举Controller成功之后;2. Broker启动或下线时;3. Unclean Leader选举时。 okay,你同意这个说法吗?或者说你有其他的看法吗?我们可以一起讨论下。
    共 1 条评论
    
  • 伯安知心
    2020-06-06
    首先声明TimingWheel不是线程安全的,addOverflowWheel这个方法设计本身要单例模式,但是多个线程执行addOverflowWheel方法,可能出现不一致实例化多个类,如果是volatile限制了指令重排序,就解决了这个问题。首先声明TimingWheel不是线程安全的,addOverflowWheel这个方法设计本身要单例模式,但是多个线程执行addOverflowWheel方法,可能出现不一致实例化多个类,如果是volatile限制了指令重排序,就解决了这个问题。

    作者回复: 不妨写个改进的patch:)

    共 2 条评论
    2
  • 李
    2020-11-15
    老师,你好。源码中TimerTaskList#add()方法中有两行这样的注释 Remove the timer task entry if it is already in any other list,We do this outside of the sync block below to avoid deadlocking. 如果timerTaskEntry.remove()该行放进timerTaskEntry.synchronized 代码块里,与其他方法加锁顺序都一致,这儿哪里会有死锁

    作者回复: 嗯,有一定道理。我觉得更多的就是一种防御性编程

    
    
  • 对与错
    2020-10-22
    我还是没有get到这个延迟队列的用途,为啥更新过期时间之后,需要把任务放到延迟队列里面?

    作者回复: 其实只是把任务放入更高一级的时间轮中管理

    共 2 条评论
    
  • 吃饭饭
    2020-06-19
    有个问题不明白:TimerTaskEntry 的 remove() 方法的 while (currentList != null) ,这个链表不是能放很多 TimerTaskEntry 吗?只是移除当前这个 Entry 为什么要把整个链表置空?如果内部还有其他的 Entry 呢?

    作者回复: 这是从TimerTaskEntry的角度去做的。currentList只是TimerTaskEntry角度下的链表,将它置空相当于把该entry与list割裂开来。链表本身还是存在的

    
    
  • RonnieXie
    2020-06-07
    老师,这里有一个疑问,使用哈希表map似乎也可以实现延迟队列,key为时间戳,定期执行任务和删除过期任务,时间复杂度O(1),请问使用分层时间轮和哈希表map的优缺点是什么?

    作者回复: 如何解决排序问题呢?

    共 3 条评论
    
  • 空知
    2020-06-07
    只有当前时间越过了 Bucket 的起始时间,这个 Bucket 才算是过期。而这里的起始时间,就是代码中 expiration 字段的值。 这里的起始时间是否应该是 终止时间? taskCounter:这一层时间轮上的总定时任务数。 这里是否是每个Bucket的任务数?

    作者回复: 1. 源码中并没有终止时间的提法。一旦时钟越过了Bucket起始时间,该Bucket就被视为过期了 2. 不是单个Bucket的,而是整个时间轮上的

    
    
  • 飞翔
    2022-09-20 来自美国
    老师 如果放在时间轮的消息太多超过内存 kafka会把消息先存在disk中嘛
    
    
  • 凯文小猪
    2022-06-29
    overflowWheel用在两个地方,一个是外部定时器也就是tickout线程的定时发起时钟轮转,此时需要更新层级时间轮(包括子级与父级),另一个是添加线程,也就是kafka接收到produceRequest的handler线程,他们会创建延时任务,如果牵涉到父级时间轮,也需要照顾他们的可见性。 这里要补充一点,就是老师没有讲到的queue问题。实际上分层时间轮最常见的问题有两个: 1.空转。也就是currentTime指针指向了某个bucket 但是那个bucket实际上是空的。kafka的处理方式使用delayqueue来处理,delayQueue.poll() 对于未到期的数据 是不会返回的,这样我们就不需要更新空转的指针 2.精度问题。实际上精度取决于最低一级时间轮的时间跨度,相当于PC里的HZ。而外部定时器每一轮发起的频次也会影响。 综上 进度误差在:外部定时器每一轮的频次+最低一级时间轮的时间跨度——》就是最小误差精度
    
    
  • innocent
    2020-12-17
    JDK自带的任务调度没有使用时间轮而是使用了优先队列
    
    