首页 > 编程语言 >抖音面试:说说延迟任务的调度算法?

抖音面试:说说延迟任务的调度算法?

时间:2024-06-05 15:24:57浏览次数:29  
标签:slot HashedWheelBucket HashedWheelTimer 面试 任务 抖音 时间 round 延迟

Netty 框架是以性能著称的框架,因此在它的框架中使用了大量提升性能的机制,例如 Netty 用于实现延迟队列的时间轮调度算法就是一个典型的例子。使用时间轮调度算法可以实现海量任务新增和取消任务的时间度为 O(1),那么什么是时间轮调度算法呢?接下来我们一起来看。

1.延迟任务实现

在 Netty 中,我们需要使用 HashedWheelTimer 类来实现延迟任务,例如以下代码:

public class DelayTaskExample {
    public static void main(String[] args) {
        System.out.println("程序启动时间:" + LocalDateTime.now());
        NettyTask();
    }

    private static void NettyTask() {
        // 创建延迟任务实例
        HashedWheelTimer timer = new HashedWheelTimer(3, // 间隔时间
                TimeUnit.SECONDS, // 间隔时间单位
                100); // 时间轮中的槽数
        // 创建任务
        TimerTask task = new TimerTask() {
            @Override
            public void run(Timeout timeout) throws Exception {
                System.out.println("执行任务时间:" + LocalDateTime.now());
            }
        };
        // 将任务添加到延迟队列中
        timer.newTimeout(task, 0, TimeUnit.SECONDS);
    }
}

以上程序的执行结果如下:

程序启动时间:2024-06-04T10:16:23.033
执行任务时间:2024-06-04T10:16:26.118

从上述执行结果可以看出,我们使用 HashedWheelTimer 实现了延迟任务的执行。

2.时间轮调度算法

那么问题来了,HashedWheelTimer 是如何实现延迟任务的?什么是时间轮调度算法?

查看 HashedWheelTimer 类的源码会发现,其实它是底层是通过时间轮调度算法来实现的,以下是 HashedWheelTimer 核心实现源码(HashedWheelTimer 的创建源码)如下:

private static HashedWheelBucket[] createWheel(int ticksPerWheel) {
    // 省略其他代码
    ticksPerWheel = normalizeTicksPerWheel(ticksPerWheel);
    HashedWheelBucket[] wheel = new HashedWheelBucket[ticksPerWheel];
    for (int i = 0; i < wheel.length; i ++) {
        wheel[i] = new HashedWheelBucket();
    }
    return wheel;
}
private static int normalizeTicksPerWheel(int ticksPerWheel) {
    int normalizedTicksPerWheel = 1;
    while (normalizedTicksPerWheel < ticksPerWheel) {
        normalizedTicksPerWheel <<= 1;
    }
    return normalizedTicksPerWheel;
}
private static final class HashedWheelBucket {
    private HashedWheelTimeout head;
    private HashedWheelTimeout tail;
    // 省略其他代码
}

在 HashedWheelTimer  中,使用了 HashedWheelBucket 数组实现时间轮的概念,每个 HashedWheelBucket 表示时间轮中一个 slot(时间槽),HashedWheelBucket 内部是一个双向链表结构,双向链表的每个节点持有一个 HashedWheelTimeout 对象,HashedWheelTimeout 代表一个定时任务,每个 HashedWheelBucket 都包含双向链表 head 和 tail 两个 HashedWheelTimeout 节点,这样就可以实现不同方向进行链表遍历,如下图所示:
image.png
时间轮算法的设计思想就来源于钟表,如上图所示,时间轮可以理解为一种环形结构,像钟表一样被分为多个 slot 槽位。每个 slot 代表一个时间段,每个 slot 中可以存放多个任务,使用的是链表结构保存该时间段到期的所有任务。时间轮通过一个时针随着时间一个个 slot 转动,并执行 slot 中的所有到期任务。

任务的添加是根据任务的到期时间进行取模,然后将任务分布到不同的 slot 中。如上图所示,时间轮被划分为 8 个 slot,每个 slot 代表 1s,当前时针指向 2 时,假如现在需要调度一个 3s 后执行的任务,应该加入 2+3=5 的 slot 中;如果需要调度一个 12s 以后的任务,需要等待时针完整走完一圈 round 零 4 个 slot,需要放入第 (2+12)%8=6 个 slot。

那么当时针走到第 6 个 slot 时,怎么区分每个任务是否需要立即执行,还是需要等待下一圈 round,甚至更久时间之后执行呢?所以我们需要把 round 信息保存在任务中。例如图中第 6 个 slot 的链表中包含 3 个任务,第一个任务 round=0,需要立即执行;第二个任务 round=1,需要等待 18=8s 后执行;第三个任务 round=2,需要等待 28=8s 后执行。所以当时针转动到对应 slot 时,只执行 round=0 的任务,slot 中其余任务的 round 应当减 1,等待下一个 round 之后执行。

可以看出时间轮有点类似 HashMap,如果多个任务如果对应同一个 slot,处理冲突的方法采用的是拉链法。在任务数量比较多的场景下,适当增加时间轮的 slot 数量,可以减少时针转动时遍历的任务个数。

时间轮定时器最大的优势就是,任务的新增和取消都是 O(1) 时间复杂度,而且只需要一个线程就可以驱动时间轮进行工作。

课后思考

Netty 中的时间轮调度算法有什么缺点?

参考 & 鸣谢

《Netty核心原理剖析与RPC实践》

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

标签:slot,HashedWheelBucket,HashedWheelTimer,面试,任务,抖音,时间,round,延迟
From: https://www.cnblogs.com/vipstone/p/18233089

相关文章

  • 神话的呼唤/Call of Myth游玩延迟高、联机延迟高的解决办法
    神话的呼唤/CallofMyth是一款架空历史题材的卡牌类游戏,以恐怖神话为背景,玩家将进入到一个充满危险的漆黑世界中,玩家需要凭借自己的智慧,挑战古老的旧神和它们狂热的信徒。近期很多玩家在游戏时遇到延迟高的情况,影响游戏体验,下面分享几种解决高延迟的方法,帮助大家流畅游玩。......
  • [数据仓库] 在抖音集团,存储实时数仓这样建 [转]
    0序在直播、电商等业务场景中存在着大量实时数据,这些数据对业务发展至关重要。而在处理实时数据时,我们也遇到了诸多挑战,比如实时数据开发门槛高、运维成本高以及资源浪费等。此外,实时数据处理比离线数据更复杂,需要应对多流JOIN、维度表变化等技术难题,并确保系统的稳定性和数据......
  • 用Redisson的延迟队列RDelayedQueue处理延迟任务或者定时任务
    什么是RedissonRedisson在基于NIO的Netty框架上,充分的利用了Redis键值数据库提供的一系列优势,在Java实用工具包中常用接口的基础上,为使用者提供了一系列具有分布式特性的常用工具类。什么是RDelayedQueue获取RDelayedQueue:public<V>RDelayedQueue<V>getDelayedQueue(R......
  • 人魅延迟高/无法联机的解决方法 人魅联机失败、联机有延迟怎么办
    人魅作为一款多人联机的恐怖解谜游戏,不仅具有极高的游戏性和趣味性,还能够锻炼玩家的观察力和团队合作能力。四个玩家需要扮演自己的角色,在小镇里探索解密,只有齐心协力,才能成功破解谜题,揭开真相。这一点来说,或许有点像剧本杀。不过,目前人魅在steam上面的评价并不是很好,大多数玩......
  • 产品面试..5毛钱的:如何把刮胡刀卖给张飞?
    这个问题其实很有意思,和“把梳子卖给和尚”、“把拖鞋卖给非洲人”本质的内容是一样,一方面考察你能否从商业角度去思考问题,更重要的,是考察你能否从不同角度去分析用户需求,给出更为“创新性”的回答。同时,也能“测试”面试者现场应变能力和逻辑推导能力,当遇到难题时表现出的心......
  • 赶紧收藏!2024 年最常见 20道 Kafka面试题(八)
    上一篇地址:赶紧收藏!2024年最常见20道Kafka面试题(七)-CSDN博客十五、Kafka中生产者运行流程是怎样的?Kafka生产者的运行流程涉及多个步骤,这些步骤确保了消息能够高效、可靠地从生产者发送到Kafka集群。以下是生产者运行流程的详细步骤:初始化:首先,生产者需要初始化,这包括设......
  • 国际版 抖音tiktok实战课程,向海外抖音出发(15节课)
    亲爱的朋友们,你们是否梦想着让自己的创意在全球舞台上闪耀?是否想要在国际版抖音TikTok上建立自己的影响力?那么,你来对地方了!我们的TikTok实战课程将带你启程,从基础到进阶,一步步解锁海外抖音的无限可能。准备好了吗?让我们携手踏上这场充满乐趣和挑战的旅程!课程概览:第1课:点......
  • 国际版 抖音tiktok实战课程,向海外抖音出发(15节课)
    课程目录1-点线传媒在9月17日15kctok速成免费课程_1.mp42-tiktok基础课程(学习如何快速破百,万播放和快速涨粉)1.mp43-tiktok实操课程一(教大家如何去网络搭建和环境设置)_1.mp44-tiktok实操课程二(批量注册邮箱)_1.mp47-tiktok进阶课程前言(内容运营、团队搭建、矩阵玩法、商业......
  • Java面试八股文day02
    系列文章目录文章目录前言跟着我的节奏拿下Java面试八股文二、容器1.java容器都有哪些?2.Collection和Collections有什么区别?java.util.Collection是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java......
  • 面试题--this关键字
    this指向是前端面试中的常问题型,简单分析为以下几种:1.在全局作用域中,this关键字固定指向全局对象window或者global。2.在函数作用域中,取决于函数是如何被调用的。    1)函数直接调用,this指向全局对象。    2)通过一个对象的属性调用,格式为对象.属性(......