手把手教你针对层级时间轮(TimingWheel)延时队列的实战落地

news2024/11/16 13:47:27

承接上文

承接上文,让我们基本上已经知道了「时间轮算法」原理和核心算法机制,接下来我们需要面向于实战开发以及落地角度进行分析如何实现时间轮的算法机制体系。

前言回顾

什么是时间轮

  • 调度模型:时间轮是为解决高效调度任务而产生的调度模型/算法思想。
  • 数据结构:通常由hash表和双向链表实现的数据结构。

为什么用时间轮?

对比传统队列的优势

相比传统的队列形式的调度器来说,时间轮能够批量高效的管理各种延时任务、周期任务、通知任务等等。例如延时队列/延时任务体系

延时任务/队列体系

延时任务、周期性任务,应用场景主要在延迟大规模的延时任务、周期性的定时任务等。

案例-Kafka的延时操作系列

比如,对于耗时的网络请求(比如Produce时等待ISR副本复制成功)会被封装成DelayOperation进行延迟处理操作,防止阻塞Kafka请求处理线程,从而影响效率和性能。

传统队列带来的性能问题

Kafka没有使用传统的队列机制(JDK自带的Timer+DelayQueue实现)。因为时间复杂度上这两者插入和删除操作都是 O(logn),不能满足Kafka的高性能要求。

基于JDK自带的Timer+DelayQueue实现

JDK Timer和DelayQueue底层都是个优先队列,即采用了minHeap的数据结构,最快需要执行的任务排在队列第一个,不一样的是Timer中有个线程去拉取任务执行,DelayQueue其实就是个容器,需要配合其他线程工作。

ScheduledThreadPoolExecutor是JDK的定时任务实现的一种方式,其实也就是DelayQueue+池化线程的一个实现。

基于时间轮TimeWheel的实现

时间轮算法的插入删除操作都是O(1)的时间复杂度,满足了Kafka对于性能的要求。除了Kafka以外,像 Netty 、ZooKeepr、Dubbo等开源项目、甚至Linux内核中都有使用到时间轮的实现。

当流量小时,使用DelayQueue效率更高。当流量大事,使用时间轮将大大提高效率。

时间轮算法是怎么样的,算法思想是什么?

时间轮的数据结构

数据结构模型主要由:时间轮环形队列和时间轮任务列表组成。

  • 时间轮(TimingWheel) 是一个存储定时任务的环形队列(cycle array),底层采用环形数组实现,数组中的每个元素可以对应一个时间轮任务任务列表(TimeWheelTaskList)

  • 时间轮任务任务列表(TimeWheelTaskList) 是一个环形的双向链表,其中的每个元素都是延时/定时任务项(TaskEntry),其中封装了任务基本信息和元数据(Metadata)。
    在这里插入图片描述
    可以看到图中的几个参数:

  • startMs: 开始时间

  • tickMs: 时间轮执行的最小单位。时间轮由多个时间格组成,每个时间格代表当前时间轮的基本时间跨度就是tickMs。

  • wheelSize: 时间轮中环形队列的数量。时间轮的时间格数量是固定的,可用wheelSize来表示。

  • interval:时间轮的整体时间跨度 = tickMs * wheelSize

根据上面这两个属性,我们就可以讲整个时间轮的总体时间跨度(interval)可以通过公式tickMs × wheelSize计算得出。例如果时间轮的tickMs=1ms,wheelSize=20,那么可以计算得出interval为20ms。

currentTime游标指针

此外,时间轮还有一个游标指针,我们称之为(currentTime),它用来表示时间轮当前所处的时间,currentTime是tickMs的整数倍。

整个时间轮的总体跨度是不变的,随着指针currentTime的不断流动,当前时间轮所能处理的时间段也在不断后移,整个时间轮的时间范围在currentTime和currentTime+interval之间。

currentTime可以将整个时间轮划分为到期部分和未到期部分,currentTime当前指向的时间格也属于到期部分,表示刚好到期,需要处理此时间格所对应的TimeWheelTaskList中的所有任务。

currentTime游标指针的运作流程

  1. 初始情况下表盘指针currentTime指向时间格0,此时有一个定时为2ms的任务插入进来会存放到时间格为2的任务列表中。
  2. 随着时间的不断推移,指针currentTime不断向前推进,过了2ms之后,当到达时间格2时,就需要将时间格2所对应的任务列表中的任务做相应的到期操作。
  3. 此时若又有一个定时为8ms的任务插入进来,则会存放到时间格10中,currentTime再过8ms后会指向时间格10。

总之,整个时间轮的总体跨度是不变的,随着指针currentTime的不断推进,当前时间轮所能处理的时间段也在不断后移,总体时间范围在currentTime和currentTime+interval之间。

层次化时间轮机制

如果当提交了超过整体跨度(interval)的延时任务,如何解决呢?因此引入了层级时间轮的概念,当任务的到期时间超过了当前时间轮所表示的时间范围时,就会尝试添加到层次时间轮中。

层次化时间轮实现原理介绍

在这里插入图片描述

层次化时间轮任务升级跃迁

在任务插入时,如果第一层时间轮不满足条件,就尝试插入到高一层的时间轮,以此类推。

  • 第一层的时间轮tickMs=1ms, wheelSize=20, interval=20ms
  • 第二层的时间轮的tickMs为第一层时间轮的interval,即为20ms

第一层和第二层时间轮的wheelSize是固定的,都是20,那么第二层的时间轮的总体时间跨度interval为400ms。正好是第一层时间轮的20倍。以此类推,这个400ms也是第三层的tickMs的大小,第三层的时间轮的总体时间跨度为8000ms。

  • 第N层时间轮走了一圈,等于N+1层时间轮走一格。即高一层时间轮的时间跨度等于当前时间轮的整体跨度。

层次化时间轮任务降级跃迁

随着时间推进,也会有一个时间轮降级的操作,原本延时较长的任务会从高一层时间轮重新提交到时间轮中,然后会被放在合适的低层次的时间轮当中等待处理;

案例介绍

层次化时间轮任务升级跃迁

例如:350ms的定时任务,显然第一层时间轮不能满足条件,所以就升级到第二层时间轮中,最终被插入到第二层时间轮中时间格17所对应的TimeWheelTaskList中。如果此时又有一个定时为450ms的任务,那么显然第二层时间轮也无法满足条件,所以又升级到第三层时间轮中,最终被插入到第三层时间轮中时间格1的TimeWheelTaskList中。

层次化时间轮任务降级跃迁

在 [400ms,800ms) 区间的多个任务(比如446ms、455ms以及473ms的定时任务)都会被放入到第三层时间轮的时间格1中,时间格1对应的TimerTaskList的超时时间为400ms

随着时间的流逝,当次TimeWheelTaskList到期之时,原本定时为450ms的任务还剩下50ms的时间,还不能执行这个任务的到期操作。

这里就有一个时间轮降级的操作,会将这个剩余时间为50ms的定时任务重新提交到层级时间轮中,此时第一层时间轮的总体时间跨度不够,而第二层足够,所以该任务被放到第二层时间轮到期时间为[40ms,60ms)的时间格中。

再经历了40ms之后,此时这个任务又被“察觉”到,不过还剩余10ms,还是不能立即执行到期操作。所以还要再有一次时间轮的降级,此任务被添加到第一层时间轮到期时间为[10ms,11ms)的时间格中,之后再经历10ms后,此任务真正到期,最终执行相应的到期操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/438763.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Delphi大师弗兰克·宝兰德(Frank Borland)回来了!

弗兰克宝兰德(Frank Borland) begin 弗兰克宝兰德(Frank Borland)的名字其实代表的是我们这些长期坚守Delphi的老程序员。但并非所有Delphi新开发人员都熟悉Borland。 弗兰克宝兰德是谁?他来自哪里?他的主…

动力节点Springsecurity笔记01-05认证入门

1 问题 如何保护我们的程序? 1.1 创建code目录 目的:后面的security工程均在此目录下学习 创建code目录,并使用idea打开 1.2 不使用安全框架的springboot web程序 1.2.1 新建子模块springboot-01-hello [外链图片转存失败,源站可能有防盗…

全志V85x MPP模块概述以及编译sample步骤

本文转载自:https://bbs.aw-ol.com/topic/3286/ 1. MPP 模块概述 MPP 系统控制模块,根据芯片特性,完成硬件各个部件的复位、基本初始化工作,同时负责完成 MPP(Media Process Platform 媒体处理平台)系统各…

索引失效了?看看这几个常见的原因!

索引是 MySQL 数据库中优化查询性能的重要工具,通过对查询条件和表数据的索引,MySQL可以快速定位数据,提高查询效率。但是,在实际的数据库开发和维护中,我们经常会遇到一些情况,导致索引失效,从…

2、八个JS中你见过的类型

1、前言 为一个变量指定类型的语法是使用"变量: 类型"的形式,如下: let num: number 123如果你没有为这个变量指定类型,编译器会自动根据你赋给这个变量的值来推断这个变量的类型: let num 123 num abc // error 不…

最简洁快速的kaggle注册(无需翻墙)

目录 1.打开浏览器,点击搜索栏最后3个点点 2.点击扩展,会到一个新页面 3.搜索获取(安装插件) 4.获取之后,网页搜索栏右边会出现该插件: 5.点击管理: 6.在下载规则中,填入下面的地…

SpringBoot整合JWT

一、What is JWT? Json web token (JWT),是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519),该 token 被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场…

认识Spring 和 IoC

目录 何为Spring 1. 何为容器 2. 何为 IoC 2.1 传统的程序开发:耦合性太高 2.2 解决传统开发中的缺陷 2.3 对比总结:IoC的实现思想 3. 理解Spring IoC 4. 理解 DI 5. 总结 何为Spring Spring是一个包含了众多工具方法的 IoC 容器&#xff1…

【Scala入门】Scala下载及安装(Windows)以及Idea创建第一个scala项目

目录 一、安装准备 二、Scala下载安装 三、Idea 创建Scala项目 一、安装准备 在安装之前,确保你的电脑上装有Jdk 8(Jdk 1.8),且环境变量配置正确。如果没有安装Jdk,请参照其他文章先安装Jdk 8(Jdk 1.8&a…

vue3之Teleport传送组件

一、前言 Teleport 是 Vue3.x 新推出的功能, 没听过这个词的小伙伴可能会感到陌生;翻译过来是传送的意思,可能还是觉得不知所以,没事下边我就给大家形象的描述一下。 二、Teleport 是什么呢?干嘛用的? T…

【PMP】敏捷项目月报模板

敏捷项目月报怎么写呢?和普通项目周报有什么不同呢?不知道大家思考过没有? 为此咱们把敏捷项目月报和普通项目月报进行了对比,并且给出了一个参考月报模板和实例,供大家参考。 敏捷项目月报模板 [项目名称]敏捷月报 …

大屏如何打造智慧城市?30张大屏模板送你,零代码基础也会用

超500个智慧城市在路上了 根据国际数据公司(IDC)最新发布的《全球半年度智慧城市支出指南》显示,2023年全球智慧城市支出预计将达到1895亿美元。中国智慧城市市场在2023年规模将达到389.2亿美元,超过全球平均水平 德勤咨询发布的一…

电脑端(PC)按键精灵——3.其他命令

电脑端(PC)按键精灵——3.其他命令 前两节说了安装、键盘和鼠标命令,这一章说下其他命令 按键精灵小白入门详细教程: 电脑端(PC)按键精灵—小白入门 详细教程 命令介绍 1. Delay 延时 简介 //1秒=1000毫秒, 1分钟=60000毫秒,…

段式内存管理VS页式内存管理

在讲解段式内存管理、页式内存管理之前,需要了解X86体系结构中的实模式和保护模式相关内容。 在 X86 架构诞生之初,其实是没有虚拟内存的概念的。1978 年发行的 8086 芯片是 X86 架构的首款芯片,它在内存管理上使用的是直接访问物理内存的方…

Java版本-招投标采购系统源代码-高效管控招采流程-降低采购成本

项目说明 随着公司的快速发展,企业人员和经营规模不断壮大,公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境,最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范,以及…

Java数据结构和算法之第五章、LinkedList与链表

一、ArrayList的缺陷 public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable {// ... // 默认容量是10private static final int DEFAULT_CAPACITY 10;//... // 数组&#xff1a;用来存储…

分布式链路追踪之SkyWalking

一 链路追踪简介 在微服务架构中&#xff0c;一次请求往往涉及到多个模块&#xff0c;多个中间件&#xff0c;多台机器的相互协作才能完成。这一系列调用请求中&#xff0c;有些是串行的&#xff0c;有些是并行的&#xff0c;那么如何确定这个请求背后调用了哪些应用&#xff0…

self-attention和cross-attention

为什么Self-Attention要通过线性变换计算Q K V&#xff0c;背后的原理或直观解释是什么&#xff1f; - 知乎回答题主问题题主的问题: 在attention中都经过一个映射&#xff0c;那么建模的相似度是否就没有意义了&#xff1f;个人感觉这…https://www.zhihu.com/question/592626…

是面试官放水,还是公司实在是太缺人?这都没挂,腾讯原来这么容易进···

本人211非科班&#xff0c;之前在字节和腾讯实习过&#xff0c;这次其实没抱着什么特别大的希望投递&#xff0c;没想到腾讯可以再给我一次机会&#xff0c;还是挺开心的。 本来以为有个机会就不错啦&#xff01;没想到能成功上岸&#xff0c;在这里要特别感谢帮我内推的同学&…

CANFD和CAN的区别

文章目录 概念速率数据长度帧格式 概念 FD全称是 Flexible Data-Rate&#xff0c;顾名思义&#xff0c;表示CAN-FD 的帧报文具有数据场波特率可变的特性&#xff0c;即 仲裁场和数据控制场使用标准的通信波特率&#xff0c;而到数据场就会切换为更高的通信波特率&#xff0c; …