【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理

news2024/12/24 2:36:24

文章目录

    • 前言
    • 参考目录
    • 版本说明
    • 学习笔记
      • 1、概述
      • 2、基于调用关系的流量控制(流控模式)
      • 2.1、流量规则 `FlowRule`
      • 2.2、选择节点
      • 3、基于QPS/并发数的流量控制(流控效果)
      • 3.1、默认方式(直接拒绝)
      • 3.2、冷启动 Warm Up
      • 3.3、匀速排队

前言

打开 Sentinel 官方文档的介绍,概括性的一句话便是:

Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。

主要以流量为切入点,流量控制是这个框架的一个重要功能,因此本文结合框架wiki 文档,对流量控制的相关方法源码进行简单的整理说明。

参考目录

  • Sentinel 官方文档
  • 流量控制
    本文主要参考的文档,在该文档基础上进行知识整理。
  • 限流 冷启动
  • 流量控制 匀速排队模式
  • 《实战Alibaba Sentinel:深度解析微服务高并发流量治理》
    结合该书对一些知识点的梳理。

版本说明

  • SentinelV1.8.6

学习笔记

1、概述

对于概述部分,wiki 文档进行了很好的说明:

在这里插入图片描述

wiki 下文主要介绍了两种流量控制的方式:

  • 基于 QPS/并发数 的流量控制
  • 基于调用关系的流量控制

本文流量控制的入口方法位于 FlowSlot,按照方法调用的先后顺序,先说明 基于调用关系的流量控制,再对 基于 QPS/并发数 的流量控制 进行展开。

在这里插入图片描述

2、基于调用关系的流量控制(流控模式)

基于调用关系的流量控制主要有三种:

  • 根据调用方限流 RuleConstant.STRATEGY_DIRECT
  • 根据调用链路入口限流:链路限流 RuleConstant.STRATEGY_CHAIN
  • 具有关系的资源流量控制:关联流量控制 RuleConstant.STRATEGY_RELATE

从方法 FlowSlot#checkFlow 一路深入,看看如何选择不同的流控模式。

FlowRuleChecker#checkFlow
在这里插入图片描述

该方法根据资源名称获取所有的限流规则,canPassCheck 循环判断是否通过。

FlowRuleChecker#canPassCheck
在这里插入图片描述

2.1、流量规则 FlowRule

在方法 FlowRuleChecker#checkFlow 中,从 ruleProvider 获取流量规则集合:

Collection<FlowRule> rules = ruleProvider.apply(resource.getName());

FlowSlot#ruleProvider
在这里插入图片描述

ruleProvider 是一个函数变量,是一个实现了 Function 接口的匿名内部类,并重写了其中的 apply 方法,用于根据资源名称获取到对应的流控规则列表。

流控规则可以自定义配置,通过监听器来更新。

FlowRuleManager.FlowPropertyListener
在这里插入图片描述

2.2、选择节点

FlowRuleChecker#selectNodeByRequesterAndStrategy

在这里插入图片描述

根据请求方法和限流策略选择节点:

  1. 获取限流应用 limitApp、策略 strategy 和请求方信息 origin
  2. 限流应用与请求方相同,并且通过过滤器验证通过:
    • RuleConstant.STRATEGY_DIRECT:返回 origin statistic node 源节点
    • selectReferenceNode
  3. 限流应用为默认应用:
    • RuleConstant.STRATEGY_DIRECT:返回 cluster node 簇点
    • selectReferenceNode
  4. 限流应用为其他应用,并且请求方与资源不同源:
    • RuleConstant.STRATEGY_DIRECT:返回 origin statistic node 源节点
    • selectReferenceNode
  5. 返回 null

FlowRuleChecker#selectReferenceNode
在这里插入图片描述

选择参考节点:

  1. 获取参考资源和策略信息
  2. 参考资源为空,则返回null
  3. RuleConstant.STRATEGY_RELATE(关联模式):
    返回 ClusterBuilderSlot.getClusterNode(refResource) 簇点
  4. RuleConstant.STRATEGY_CHAIN(链路模式):
    比较参考资源和请求方名称,如果不相等,则返回 null,否则,返回默认节点。
  5. 返回 null

3、基于QPS/并发数的流量控制(流控效果)

并发线程数控制比较简单:
在这里插入图片描述

下面主要是QPS流量控制的三种方式:

  • 直接拒绝
  • Warm Up
  • 匀速排队

在这里插入图片描述

流控通用接口 TrafficShapingController
在这里插入图片描述

在构建限流规则集合时,底层方法如下:

FlowRuleUtil#buildFlowRuleMap
在这里插入图片描述

FlowRuleUtil#generateRater
在这里插入图片描述

根据不同的规则,有不同的限流方式,下面按照顺序来说明。

3.1、默认方式(直接拒绝)

直接拒绝(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。

DefaultController#canPass
在这里插入图片描述

该方法的主要逻辑:

  1. 首先,获取节点当前平均使用的令牌数量。然后,检查当前令牌数量加上希望占用的令牌数量是否超过了节点的总令牌数量。如果超过了,则根据优先处理和流控等级的条件判断是否需要等待。
  2. 如果需要优先处理且流控等级为 QPS 级别,那么获取当前时间和下一次尝试占用令牌的等待时间。如果等待时间小于占用超时的时间,则将当前时间加上等待时间作为等待请求的时间,并将希望占用的令牌数量添加到节点的等待请求中,并将希望占用的令牌数量添加到节点的占用通过数量中。然后,根据等待时间进行睡眠。
  3. 最后,抛出一个 PriorityWaitException 异常,表示请求将在等待一段时间后通过。
  4. 如果不需要等待或者等待时间超过了占用超时的时间,则返回 false,表示节点无法通过。
  5. 如果当前令牌数量加上希望占用的令牌数量不超过节点的总令牌数量,则返回 true,表示节点可以通过。

在这里插入图片描述

StatisticNode#tryOccupyNext
在这里插入图片描述

该方法主要是尝试占用令牌,入参为当前时间、希望获取的令牌数量、阈值,返回下一次尝试占用令牌的等待时间。主要逻辑如下:

  1. 首先,根据阈值和时间间隔计算最大令牌数量。阈值 threshold 是一个百分比,表示每秒允许占用的最大令牌数量。时间间隔 IntervalProperty.INTERVAL 是一个固定的时间段,用于计算令牌的窗口长度。
double maxCount = threshold * IntervalProperty.INTERVAL / 1000;
  1. 接下来,获取当前等待的令牌数量。如果当前等待的令牌数量已经超过了最大令牌数量,那么直接返回占用超时的时间。
long currentBorrow = rollingCounterInSecond.waiting();
  1. 然后,计算窗口长度。窗口长度是时间间隔除以样本数量,用于划分时间窗口。
int windowLength = IntervalProperty.INTERVAL / SampleCountProperty.SAMPLE_COUNT;
  1. 接着,计算最早的时间点。最早的时间点是当前时间减去当前时间与窗口长度的余数,加上窗口长度减去时间间隔。这样可以得到上一个时间窗口的起始时间。
long earliestTime = currentTime - currentTime % windowLength + windowLength - IntervalProperty.INTERVAL;
  1. 然后,初始化一个索引变量 idx,用于迭代时间窗口。接下来,获取当前通过的令牌数量。
    (注释部分)注意,由于调用了rollingCounterInSecond.pass()方法之后可能经过了一段时间,所以当前通过的令牌数量可能小于实际通过的令牌数量。在高并发的情况下,这段代码可能导致更多的令牌被借用。

  2. 然后,进入一个循环,直到最早的时间点大于当前时间为止。在每次循环中,计算等待的时间。

long waitInMs = idx * windowLength + windowLength - currentTime % windowLength;
  1. 等待的时间是索引乘以窗口长度加上窗口长度减去当前时间与窗口长度的余数。如果等待的时间大于等于占用超时的时间,那么退出循环。
  2. 接着,获取窗口通过的令牌数量。如果当前通过的令牌数量加上当前借用的令牌数量加上希望占用的令牌数量减去窗口通过的令牌数量小于等于最大令牌数量,那么返回等待的时间。
long windowPass = rollingCounterInSecond.getWindowPass(earliestTime);
  1. 然后,更新最早的时间点,将其加上窗口长度。同时,将当前通过的令牌数量减去窗口通过的令牌数量。索引变量加1。
  2. 最后,如果没有找到合适的时间窗口,则返回占用超时的时间。

3.2、冷启动 Warm Up

在这里插入图片描述

在这里插入图片描述

WarmUpController#canPass
在这里插入图片描述

该方法的主要逻辑:

  1. 首先,获取节点的当前通过 QPS 和上一个通过 QPS。然后,调用 syncToken 方法同步令牌。
long passQps = (long) node.passQps();
long previousQps = (long) node.previousPassQps();
syncToken(previousQps);

在这里插入图片描述


syncToken 方法用于更新令牌桶中的令牌数量。首先,获取当前时间,并将其取整到秒。然后,获取上一次填充令牌的时间。如果当前时间小于等于上一次填充令牌的时间,则直接返回。

接着,获取令牌桶中的旧令牌数量,并根据当前时间和通过QPS计算新的令牌数量。

long newValue = coolDownTokens(currentTime, passQps);

使用 compareAndSet 方法将新的令牌数量设置到令牌桶中,并更新令牌桶中的当前令牌数量。如果当前令牌数量小于0,则将其设置为0。最后,更新上一次填充令牌的时间。


  1. 然后,根据令牌桶中的令牌数量和希望占用的令牌数量进行判断,如果令牌桶中的令牌数量大于等于警戒线以上的令牌数量,即令牌消耗程度较低,那么根据令牌消耗速率和令牌数量计算警戒线以下的 QPS,并判断通过 QPS 加上希望占用的令牌数量是否小于等于警戒线以下的 QPS。如果是,则返回 true,表示节点可以通过。

  2. 如果令牌桶中的令牌数量小于警戒线以上的令牌数量,即令牌消耗程度较高,那么根据通过 QPS 和冷却因子的比较判断是否需要添加令牌。如果通过 QPS 小于总令牌数量除以冷却因子,即令牌消耗速率较低,那么根据令牌消耗速率和令牌数量计算新的令牌数量。最后,返回新的令牌数量和最大令牌数量的较小值。

  3. 返回 false

3.3、匀速排队

在这里插入图片描述

RateLimiterController#canPass
在这里插入图片描述

该方法的主要逻辑:

  1. 首先判断请求的 acquireCount 是否小于等于0,如果是的话,直接返回 true,表示可以通过。
  2. 判断资源的数量 count 是否小于等于0,如果是的话,直接返回 false,表示不能通过。
  3. 获取当前时间 currentTime。
  4. 根据请求的数量 acquireCount 和资源的数量 count 计算每两个请求之间的间隔,即 costTime。
long costTime = Math.round(1.0 * (acquireCount) / count * 1000);
  1. 计算这个请求的预计通过时间 expectedTime,即 costTime 加上最近通过的请求的时间 latestPassedTime。
long expectedTime = costTime + latestPassedTime.get();
  1. 如果 expectedTime 小于等于当前时间 currentTime,表示当前请求可以通过。这里可能会存在竞争条件,但是没有关系。将最近通过的时间 latestPassedTime设置为当前时间 currentTime,然后返回 true。
  2. 如果 expectedTime 大于当前时间 currentTime,表示当前请求需要等待一段时间才能通过。
  3. 计算需要等待的时间 waitTime,即 costTime 加上最近通过的请求的时间 latestPassedTime 减去当前时间 currentTime。
long waitTime = costTime + latestPassedTime.get() - TimeUtil.currentTimeMillis();
  1. 如果 waitTime 大于最大排队时间 maxQueueingTimeMs,则返回 false,表示不能通过。
  2. 如果 waitTime 小于等于最大排队时间,则将最近通过的时间 latestPassedTime 加上 costTime,并且尝试进行等待。
  3. 在进行等待之前,再次计算等待的时间 waitTime,即最近通过的时间 latestPassedTime 减去当前时间 currentTime。
  4. 如果 waitTime 大于最大排队时间,则将最近通过的时间 latestPassedTime 减去 costTime,并返回 false,表示不能通过。
  5. 如果 waitTime 大于0,则进行等待,等待时间为 waitTime 毫秒。
  6. 等待结束后,返回 true,表示可以通过。
  7. 如果在等待过程中被中断,则捕获 InterruptedException 异常,不做任何处理。
  8. 最后,如果以上条件都不满足,则返回 false,表示不能通过。

(完)

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

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

相关文章

数通王国历险记之数据从发出到接收的细节介绍{封装与解封装}

系列文章目录 数通王国历险记&#xff08;5&#xff09; 目录 前言 一&#xff0c;数据封装的全过程 1.1&#xff0c;应用层的封装形式 1.2&#xff0c;传输层的封装形式 理解&#xff1a; 1.3&#xff0c;网络层的封装形式 理解&#xff1a; 1.4&#xff0c;数据链路层…

Sublime Text,灵感犹如星辰,点亮创作之路

目录 引言Sublime Text的优点Sublime Text的缺点总结 Sublime Text 官方网站 引言 在这个快速发展的数字时代&#xff0c;创作者们面临着越来越多的选择&#xff0c;以提高他们的生产力和工作效率。而在众多的编辑软件中&#xff0c; Sublime Text 独树一帜&#xff0c;被誉为创…

mac怎么把m4a转换成mp3?

mac怎么把m4a转换成mp3&#xff1f;大家都知道m4a是苹果公司专属的音频文件格式&#xff0c;因此它是可以直接在mac电脑上打开播放的&#xff0c;但这并不代表m4a音频文件可以在其他播放器或者播放设备上直接打开和使用&#xff0c;相信这个问题大家都遇到过&#xff0c;造成这…

【Vivado那些事儿】动态时钟的使用

时钟是每个 FPGA 设计的核心。如果我们正确地设计时钟架构、没有 CDC 问题并正确进行约束设计&#xff0c;就可以减少与工具斗争的时间。 但对于某些应用&#xff0c;我们希望能够更改某些IP中的时钟频率。其中一个例子是在图像处理管道中&#xff0c;输出分辨率可以动态变化&a…

单片机电机控制编程操作系统环境编程与裸机编程的比较

随着单片机技术的不断发展&#xff0c;单片机在电机控制领域中的应用越来越广泛。在单片机编程中&#xff0c;有两种主要的方法&#xff1a;操作系统编程和裸机编程。本文将比较这两种方法在电机控制中的优缺点。 操作系统编程 操作系统编程需要使用操作系统&#xff0c;例如F…

Python GUI编程利器:Tkinker中的滚动条和框架(8)

小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 和猫妹学Python&#xff0c;一起趣味学编程。 今日目标 实现下面效果&#xff1a; 滚动条(Scrollbar类) 滚动条用于调整一些控件的可见范围&#xff0c;根据方向分为水平滚…

[LeetCode]2178.拆分成最多数目的偶整数之和

2178.拆分成最多数目的偶整数之和 题目 思路 首先&#xff0c;奇数是不可拆分成多数目的偶整数&#xff0c;这种情况返回一个空数组。 累加2以组合一个最多不同数目偶整数&#xff0c;当拆分的最后一个偶整数&#xff0c;总和大于原数时&#xff0c;将差值累加到最后一位偶整…

【算法设计与分析】工作分配问题——设计一个算法,对于给定的工作费用,计算最佳工作分配方案,使总费用达到最小。

目录 一、问题描述二、问题分析三、运行结果四、源代码 一、问题描述 设有n件工作分配给n个人。将工作i分配给第j个人所需要的费用是。试设计一个算法&#xff0c;为每个人都分配1件不同的工作&#xff0c;并使总费用达到最小。设计一个算法&#xff0c;对于给定的工作费用&…

LeetCode_BFS_中等_1466.重新规划路线

目录 1.题目2.思路3.代码实现&#xff08;Java&#xff09; 1.题目 n 座城市&#xff0c;从 0 到 n-1 编号&#xff0c;其间共有 n-1 条路线。因此&#xff0c;要想在两座不同城市之间旅行只有唯一一条路线可供选择&#xff08;路线网形成一颗树&#xff09;。去年&#xff0c…

Java Maven安装及环境配置教程

一、安装 1、安装包 apache-maven-3.6.3 安装包下载地址 2、下载安装包然后直接解压就行。 注意&#xff1a;文件的位置路径不能有中文。 二、环境配置 1、用户变量 双击Path&#xff0c;点击新建&#xff0c;将如下复制进去&#xff0c;然后点击确定&#xff1a; %MAVEN_HO…

轻量服务器域名无法解析怎么排查?

​  轻量服务器域名无法解析是指在DNS(域名系统)解析过程中&#xff0c;无法将域名转换为相应的IP地址。DNS可帮助该域名与代表该网站在互联网上的位置的数字 IP 地址相关联&#xff0c;帮助我们找到并连接到目标网站。因此&#xff0c;当我们无法解析域名时&#xff0c;就无…

CENTOS7-安装部署httpd或apache

1、在Centos中安装apache服务器 yum install httpd* -y 2、启动apache&#xff0c;可以查看运行状态&#xff0c;如图&#xff1a; 启动命令&#xff1a;systemctl status httpd.service 有active running说明已经安装好&#xff0c;并且可以正常启动。 3、设置主目录&…

SpringBoot结合Filter的登录认证退出流程(介绍后端要做的事)

交互流程 简略图 注意&#xff1a; 点击访问进入应用后前端要获取url中的openId存放在所有请求的请求头里&#xff0c;用于后端在拦截器中判断是否有openId和调用中台接口判断openId是否有效 后端 后端主要做三件事&#xff1a; 搞个拦截器用于判断是否有openId和调用中台接…

手机远程连接登录Windows桌面

RDClient远程连接&#xff0c;手机远程电脑&#xff0c;手机远程Windows&#xff0c;手机连接Windows 因为工作需求&#xff0c;笔记本不经常带在身上&#xff0c;有时候需要用手机远程连接电脑操作一下 安卓手机和IPhone手机都可以&#xff0c;用的是微软官方的Remote Deskt…

【Java】Stack和Queue的使用

文章目录 一、栈1.1 什么是栈1.2 栈的模拟实现 二、Java中的Stack2.1 构造方法2.2 操作方法2.3 应用场景 三、队列3.1 什么是队列3.2 队列的模拟实现 四、Java中的Queue4.1 实例化方法4.2 操作方法4.3 应用场景 一、栈 1.1 什么是栈 栈&#xff08;Stack&#xff09;是一种常…

VSCODE VUE3 element-ui plaus 环境搭建

目录 一、VUE 1、安装VUE 2、创建项目 二、Element Plus 1、在项目目录中安装 Element Plus&#xff0c;执行 2、引入element 三、vscode 中运行 1、打开项目文件夹 2、点击debug&#xff0c;运行 1&#xff09;、首次lanch chrome时 2&#xff09;、lanch node.js …

【python】pycharm配置Github Copilot

1.获取github的ip import socket from urllib.parse import urlparse# 通过URL获取目标服务器IP和端口号 def get_server_ip_and_port(url):# 解析URL获取域名和端口号parsed_url urlparse(url)domain parsed_url.netlocport parsed_url.port or 80try:# 进行域名解析&…

基于matlab使用光学字符识别技术识别文本(附源码)

一、前言 此示例演示如何使用计算机视觉工具箱中的函数执行光学字符识别。 二、实例 识别图像中的文本在许多计算机视觉应用程序中非常有用&#xff0c;例如图像搜索、文档分析和机器人导航。该函数提供了一种将文本识别功能添加到各种应用程序的简单方法。 函数返回已识别的…

VS2022配置OpenCV4.7.0

1、下载并解压OpenCV OpenCV与VC版本的对应关系信息&#xff1a;OpenCV解压后在\opencv\build\x64文件夹下可以看到如下文件夹&#xff1a; 其中&#xff1a;vc16 Visual Studio 2019 2、配置环境变量 双击Path进入【编辑环境变量】界面&#xff0c;新建—>浏览将opencv\b…