HashedWheelTimer详解

news2024/11/23 20:24:41

1、 前言

你好呀,我是歪歪。
今天我带大家来卷一下时间轮吧,这个玩意其实还是挺实用的。
常见于各种框架之中,偶现于面试环节,理解起来稍微有点难度,但是知道原理之后也就觉得:

在这里插入图片描述

大多数人谈到时间轮的时候都会从 netty 开始聊。
我就不一样了,我想从 Dubbo 里面开始讲,毕竟我第一次接触到时间轮其实是在 Dubbo 里面,当时就惊艳到我了。
而且,Dubbo 的时间轮也是从 Netty 的源码里面拿出来的,基本一模一样。
时间轮在 Dubbo 里面有好几次使用,比如心跳包的发送、请求调用超时时间的检测、还有集群容错策略里面。
我就从 Dubbo 里面这个类说起吧:

org.apache.dubbo.rpc.cluster.support.FailbackClusterInvoker

在这里插入图片描述

你不了解 Dubbo 也没有关系,你只需要知官网上是这样介绍它的就行了:
我想突出的点在于“ 定时重发”这四个字。
我们先不去看源码,提到定时重发的时候,你想到了什么东西?
是不是想到了定时任务?

那么怎么去实现定时任务呢?
大家一般都能想到 JDK 里面提供的 ScheduledExecutorService 和 Timer 这两个类。
Timer 就不多说了,性能不够高,现在已经不建议使用这个东西。
ScheduledExecutorService 用的还是相对比较多的,它主要有三个类型的方法:
简单说一下 scheduleAtFixedRate 和 scheduleWithFixedDelay 这两个方法。
ScheduleAtFixedRate,是每次执行时间为上一次任务开始起向后推一个时间间隔。
ScheduleWithFixedDelay,是每次执行时间为上一次任务结束起向后推一个时间间隔。

前者强调的是上一个任务的开始时间,后者强调的是上一个任务的结束时间。
你也可以理解为 ScheduleAtFixedRate 是基于固定时间间隔进行任务调度,而 ScheduleWithFixedDelay 取决于每次任务执行的时间长短,是基于不固定时间间隔进行任务调度。
所以,如果是我们要基于 ScheduledExecutorService 来实现前面说的定时重发功能,我觉得是用 ScheduleWithFixedDelay 好一点,含义为前一次重试完成后才应该隔一段时间进行下一次重试。
让整个重试功能串行化起来。
那么 Dubbo 到底是怎么实现这个定时重试的需求的呢?
撸源码啊,源码之下无秘密。
准备发车。

在这里插入图片描述

撸源码
有的同学看到这里可能着急了:不是说讲时间轮吗,怎么又开始撸源码了呀?
你别猴急呀,我这不得循序渐进嘛。
我先带你手撕一波 Dubbo 的源码,让你知道源码这样写的问题是啥,然后我再说解决方案嘛。
再说了,我直接,啪的一下,把解决方案扔你脸上,你也接受不了啊。
我喜欢温柔一点的教学方式。

在这里插入图片描述

好了,先看下面的源码。
在这里插入图片描述

这几行代码你要是没看明白没有关系,你主要关注 catch 里面的逻辑。
我把代码和官网上的介绍帮你对应了一下。
意思就是调用失败了,还有一个 addFailed 来兜底。
addFailed 是干了啥事呢?
干的就是“定时重发”这事:

org.apache.dubbo.rpc.cluster.support.FailbackClusterInvoker#addFailed

在这里插入图片描述

这个方法就可以回答前面我们提出的问题:Dubbo 集群容错里面,到底是怎么实现这个定时重试的需求的呢?
从标号为 ① 的地方可以知道,用的就是 ScheduledExecutorService,具体一点就是用的 scheduleWithFixedDelay 方法。
再具体一点就是如果集群容错采用的是 failback 策略,那么在请求调用失败的 RETRY_FAILED_PERIOD 秒之后,以每隔 RETRY_FAILED_PERIOD 秒一次的频率发起重试,直到重试成功。
RETRY_FAILED_PERIOD 是多少呢?

看第 52 行,它是 5 秒。
另外,你可以在前面 addFailed 方法中看到标号为 ③ 的地方,是在往 failed 里面 put 东西。
failed 又是一个什么东西呢?
看前面的 61 行,是一个 ConcurrentHashMap。
标号为 ③ 的地方,往 failed put 的 key 就是这一次需要重试的请求,value 是处理这一次请求对应的服务端。
failed 这个 map 是什么时候用呢?
请看标号为 ② 的 retryFailed 方法:

在这里插入图片描述

在这个方法里面会去遍历 failed 这个 map,全部拿出来再次调用一遍。
如果成功了就调用 remove 方法移除这个请求,没有成功的会抛出异常,打印日志,然后等待下次再次重试。
到这里我们就算是揭开了 Dubbo 的 FailbackClusterInvoker 类的神秘面纱。
面纱之下,隐藏的就是一个 map 加 ScheduledExecutorService。
感觉好像也没啥难的啊,很常规的解决方案嘛,我也能想到啊。
于是你缓缓的在屏幕上打出一个:
在这里插入图片描述

但是,朋友们,抓好坐稳,要“但是”了,要转弯了。
这里面其实是有问题的,最直观的就是这个 map,没有限制大小,由于没有限制大小,那么在一些高并发的场景下,是有可能出现内存溢出的。
好,那么问题来了,怎么防止内存溢出呢?
很简单,首先我们可以限制 map 的大小,对吧。
比如限制它的容量为 1000。
满了之后,怎么办呢?
可以搞一个淘汰策略嘛,先进先出(FIFO),或者后进先出(LIFO)。
然后也不能一直重试,如果重试超过了一定次数应该被干掉才对。
上面说的内存溢出和解决方案,都不是我乱说的。
我都是有证据的,因为我是从 FailbackClusterInvoker 这个类的提交记录上看到了它的演进过程的,前面截图的代码也是优化之前版本的代码,并不是最新的代码:

在这里插入图片描述

这一次提交,提到了一个编号叫 2425 的 issue。
https://github.com/apache/dubbo/issues/2425

在这里插入图片描述

这里面提到的问题和解决方案,就是我前面说的事情。
终于,铺垫完成,关于时间轮的故事要正式开始了。

时间轮原理
有的朋友又开始猴急了。
要我赶紧上时间轮的源码。
你别着急啊,我直接给你讲源码,你肯定会看懵逼的。
所以我决定,先给你画图, 给大家画一下时间轮的基本样子,理解了时间轮的工作原理,下面的源码解析理解起来也就相对轻松一点了。
首先时间轮最基本的结构其实就是一个数组,比如下面这个长度为 8 的数组:
怎么变成一个轮呢?
首尾相接就可以了:
假如每个元素代表一秒钟,那么这个 数组一圈能表达的时间就是 8 秒,就是这样的:

在这里插入图片描述

注意我前面强调的是一圈,为 8 秒。
那么 2 圈就是 16 秒, 3 圈就是 24 秒,100 圈就是 800 秒。
这个能理解吧?
我再给你配个图:
在这里插入图片描述
虽然数组长度只有 8,但是它可以在上叠加一圈又一圈,那么能表示的数据就多了。
比如我把上面的图的前三圈改成这样画:
希望你能看明白,看不明白也没有关系,我主要是要你知道这里面有一个“第几圈”的概念。
好了,我现在把前面的这个数组美化一下,从视觉上也把它变成一个轮子。
轮子怎么说?
轮子的英文是 wheel,所以我们现在有了一个叫做 wheel 的数组:

在这里插入图片描述

然后,把前面的数据给填进去大概是长这样的。
为了方便示意,我只填了下标为 0 和 3 的位置,其他地方也是一个意思:

在这里插入图片描述

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

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

相关文章

chatgpt赋能python:Python关键词用法介绍

Python关键词用法介绍 Python是一种高级编程语言,具有简洁易懂、易于学习等特点。作为一位10年的Python工程师,我发现掌握Python的关键词用法对于编程非常重要。因此,本文将重点介绍Python关键词的用法,并为您提供相关的代码示例…

iOS加固保护新思路

之前有写过【如何给iOS APP加固】,但是经过一段时间的思考,我找到了更具有实践性的代码,具体可以看下面。 技术简介 iOS加固保护是基于虚机源码保护技术,针对iOS平台推出的下一代加固产品。可以对iOS APP中的可执行文件进行深度…

小程序 自建本地数据库 本地存储

大家好哇,我是梦辛工作室的灵,在最近的开发过程中又遇到了一些问题,这次是关于本地存储的,在小程序面进行存储一些数据,本来就依靠小程序的本地储存API 就可以实现,但数据量小还好,如果数据量大…

chatgpt赋能python:Python开发:为什么适合SEO

Python开发:为什么适合SEO 在当今互联网上,搜索引擎优化(SEO)尤为重要。因为通过优化您的网站,在搜索引擎上排名更高可以增加您的网站流量和业务转化率。在这篇文章中,我们将探讨为什么Python是一个优秀的…

SpringMVC重点知识

目录 第一章 SpringMVC概念 0.引言 1.MVC 2.SpringMVC 3.SpringMVC的特点 4.JavaSE、JavaEE、javaME的区别 第二章 Spring MVC的使用 1.SpringMVC的配置 2.web.xml配置 3. 创建当前的请求控制器 4. 创建SpringMVC的配置文件 5.实现对首页index.xml的访问 6.Reques…

总结886

学习目标: 月目标:6月(张宇强化10讲,专业课,背诵15篇短文,考研核心词过三遍) 周目标:1800线性代数部分并完成错题记录,英语背3篇文章并回诵,检测&#xff0…

Throwable源码

介绍 Throwable类是Java语言中所有错误(errors)和异常(exceptions)的父类,直接子类为 Error 和 Exception。只有继承于Throwable的类或子类才能被抛出,还有一种是Java中的throw注解类也可以抛出。 public…

Stub实验

需求 将区域12设置为Stub区域,使区域12的路由设备不受外部链路影响(不接收4/5类LSA)降低区域12(末梢区域)设备压力,还能让区域12的PC1与外部PC3通信 配置步骤 1)配置接口信息 - 配置PC的IP地址 - 配置路由…

chatgpt赋能python:Python免费资料全揭秘:入门学习到深入应用

Python免费资料全揭秘:入门学习到深入应用 作为一种最具代表性的动态编程语言,Python在很多领域得到了广泛的应用,因其简单易学、开发效率快等特点而备受开发者的喜爱。如果你刚开始学习Python或是想提高你的Python编程技能,那么…

系统移植-环境搭建

安装系统 在基于ARM处理器的开发板上安装Linux系统 1.移植的目的 不同架构的处理器指令集不兼容,即便是相同的处理器架构,板卡不同驱动代码也不兼容 ; Linux是一个通用的内核并不是为某一个特定的处理器架构或板卡设计的,…

【生物力学】《人体骨肌系统生物力学》- 王成焘老师 - 第3章 - 人体运动测量与仿真分析

第2章回到目录后续暂时用不到 文章目录 3.1 概论1. 基于影像的运动捕捉技术2 . 其他运动捕捉技术 3.2 人体运动测量内容与设备3.2.1 人体运动测量内容1. 时间参数2. 空间参数3. 时空参数 3.2.2 运动捕捉系统的主要类型与工作特性1. 运动捕捉系统组成2. 运动捕捉系统主要类型与工…

chatgpt赋能python:用Python做股票分析

用Python做股票分析 在当今的股市中,数据分析和预测已经变得十分重要。Python作为最流行的编程语言之一,不仅易于学习,还有非常强大的数据处理和分析能力。在本文中,我们将探讨如何用Python进行股票分析。 数据收集 要进行股票…

Java网络开发(Tomcat)——遇到的 bug 汇总(持续更新):bug:

目录 引出:bug::bug::bug:Tomcat开发的bug汇总session不能转换成String类型在servlet的if处理流程中,没有加return后端传给jsp的数据,前端jsp不显示jsp的包没有导,用foreach方法的时候报错jsp的forEach方法报错jsp用foreach的时候&#xff0c…

chatgpt赋能python:Python免费软件:提高工作效率的首选

Python免费软件:提高工作效率的首选 Python作为一种易于上手的编程语言,在业界广为流传。而随着Python的发展,也催生了相应的一些免费软件,这些软件能够让用户更好地利用Python编程语言,提高工作效率,创造…

数据存储云安全的 5 大支柱

与任何数据存储系统一样,云也存在相当多的安全风险。领导者不应争论云本身安全或不安全的方式,而应质疑他们是否安全地使用云。 虽然云安全采用组织和云提供商之间的责任共担模式,但归根结底,云环境面临的最大风险是解决方案的错…

对数组中的所有元素进行限值指定的最小值和最大值:超过最大值的元素,则改写为最大值小于最小值的元素,则改写为最小值numpy.clip()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 对数组中的所有元素进行限值 指定的最小值和最大值: 超过最大值的元素,则改写为最大值 小于最小值的元素,则改写为最小值 numpy.clip() [太阳]选择题 请问…

大数据Doris(三十二):HDFS Load和Spark Load的基本原理

文章目录 HDFS Load和Spark Load的基本原理 一、HDFS Load 二、 Spark Load的基本原理 HDFS Load和Spark Load的基本原理 一、HDFS Load HDFS Load主要是将HDFS中的数据导入到Doris中,Hdfs load 创建导入语句,导入方式和Broker Load 基本相同&#…

(字符串 ) 剑指 Offer 05. 替换空格 ——【Leetcode每日一题】

❓剑指 Offer 05. 替换空格 难度&#xff1a;简单 请实现一个函数&#xff0c;把字符串 s 中的每个空格替换成 “%20”。 示例 1&#xff1a; 输入&#xff1a;s “We are happy.” 输出&#xff1a;“We%20are%20happy.” 限制&#xff1a; 0 < s 的长度 < 10000 …

第四章 Electron 使用SQLite3数据库

一、SQLite是什么 &#x1f447; &#x1f447; &#x1f447; SQLite是一种嵌入式关系型数据库管理系统&#xff0c;是一个零配置、无服务器的、自给自足的、事务性的SQL数据库引擎。SQLite是一个轻量级的数据库&#xff0c;可以在各种操作系统上使用&#xff0c;并且支持SQL…

区间预测 | MATLAB实现基于QRCNN-LSTM-Multihead-Attention多头注意力卷积长短期记忆神经网络多变量时间序列区间预测

区间预测 | MATLAB实现基于QRCNN-LSTM-Multihead-Attention多头注意力卷积长短期记忆神经网络多变量时间序列区间预测 目录 区间预测 | MATLAB实现基于QRCNN-LSTM-Multihead-Attention多头注意力卷积长短期记忆神经网络多变量时间序列区间预测效果一览基本介绍模型描述程序设计…