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

这篇具有很好参考价值的文章主要介绍了【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

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

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

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

参考目录

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

版本说明

  • SentinelV1.8.6

学习笔记

1、概述

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

【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

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

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

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

【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

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

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

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

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

FlowRuleChecker#checkFlow
【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

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

FlowRuleChecker#canPassCheck
【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

2.1、流量规则 FlowRule

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

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

FlowSlot#ruleProvider
【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

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

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

FlowRuleManager.FlowPropertyListener
【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

2.2、选择节点

FlowRuleChecker#selectNodeByRequesterAndStrategy

【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

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

  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
【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

选择参考节点:

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

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

并发线程数控制比较简单:
【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

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

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

【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

流控通用接口 TrafficShapingController
【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

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

FlowRuleUtil#buildFlowRuleMap
【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

FlowRuleUtil#generateRater
【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

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

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

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

DefaultController#canPass
【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

该方法的主要逻辑:

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

【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

StatisticNode#tryOccupyNext
【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

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

  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

【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

WarmUpController#canPass
【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

该方法的主要逻辑:

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

【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java


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

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

long newValue = coolDownTokens(currentTime, passQps);

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


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

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

  3. 返回 false

3.3、匀速排队

【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

RateLimiterController#canPass
【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理,框架学习 - RuoYi-Cloud-Plus,sentinel,RuoYiCloudPlus,java

该方法的主要逻辑:

  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,表示不能通过。

(完)文章来源地址https://www.toymoban.com/news/detail-530251.html

到了这里,关于【RuoYi-Cloud-Plus】学习笔记 08 - Sentinel(三)流量控制知识整理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringCloud学习6(Spring Cloud Alibaba)断路器Sentinel熔断降级

    SpringCloud、SpringCloudAlibaba、SpringBoot版本选择。为了避免各种千奇百怪的bug,我们还是采用官方推荐的毕业版本。 修改tomcat配置最大线程数 引入测试依赖 编写测试代码 这里同时我们在浏览器去请求该地址,响应会变得很慢 测试结论:此时会发现由于thread接口囤积大量请求,

    2023年04月08日
    浏览(38)
  • ruoyi-cloud部署

    默认你已经安装mysql,nacos,seata,sentinel等(没有的可以先找教程安装) 1、下载源码:git clone https://gitee.com/zhangmrit/ruoyi-cloud 2、项目依赖导入,选择自己的maven环境等,创建三个库ry-cloud、ry-config、ry-seata执行下面三个sql,把quartz放到ry-cloud 3、nacos配置,生成配置列表(配置该

    2024年02月11日
    浏览(31)
  • ruoyi cloud集成casdoor

            之前写过一篇关于ruoyi cloud集成cas的但是使用的apereo的单点登录,该应用的文档都是英文文档,尝试一下集成casdoor,其官方文档比较详细。 考虑到有些小伙伴上git不方便,需要用到的代码和Windows工具,都在这了         Go 1.6+ Node.js LTS (16或14) 这里我使用的是

    2024年02月07日
    浏览(27)
  • MySql学习笔记08——事务介绍

    事务是一个完整的业务逻辑,是一个最小的工作单元,不可再分。 一个完整的业务逻辑包括一系列的操作,这些操作是整个业务逻辑中的最小单元,这些操作要么同时成功,要么同时失败。 由于只有DML语句中才会有事务的概念,因此事务只和 insert update delete 语句有关。 说到

    2024年02月09日
    浏览(26)
  • RuoYi-Vue-Plus搭建(若依)

     项目简介 业务功能 拉取代码 建库建表 修改配置 后端启动 前端启动 项目访问(http://localhost:81) ​​ ​ ​ ​

    2024年02月11日
    浏览(22)
  • RuoYi-Flowable-Plus搭建(若依)

    项目简介 业务功能 拉取代码 建库建表 修改配置 后端启动 前端启动 项目访问(http://localhost:81) ​​ ​ 测试SQL

    2024年02月16日
    浏览(24)
  • RuoYi -Cloud开源框架-跨域配置

    🦆博主介绍:小黄鸭技术 🌈擅长领域:Java、实用工具、运维 👀 系列专栏:📢开发工具 Java之路 八股文之路 📧如果文章写作时有错误的地方,请各位大佬指正,一起进步!!! 🧡欢迎大家点赞➕收藏⭐➕评论💬支持博主🤞   目录  什么是跨域 RoYi-Cloud如何解决跨域

    2024年02月03日
    浏览(24)
  • RuoYi-Cloud微服务开发实战

    目录 第一章 开发环境搭建 前言 一、RuoYi-Cloud是什么? 二、环境部署 1.安装JDK 2.安装docker 3.下载mysql镜像 4.下载redis镜像 5.下载nacos-server 镜像 6.安装node.js 三、项目启动 开发设备:         MacBook Pro(14英寸,2021年)         系统版本:macOS Monterey         芯片:

    2024年02月16日
    浏览(33)
  • 大模型学习笔记08——分布式训练

    模型规模的扩大,对硬件(算力、内存)的发展提出要求。然而,因为内存墙的存在,单一设备的算力及容量,受限于物理定律,持续提高芯片的集成越来越困难,难以跟上模型扩大的需求。 为了解决算力增速不足的问题,人们考虑用多节点集群进行分布式训练,以提升算力

    2024年01月23日
    浏览(33)
  • ruoyi-cloud微服务新建子模块

    相关文章 官方文档 1、复制system模块 直接复制 modules下面已有的system模块,改名为 test 2、在modules下的 pom.xml文件中添加子模块 test 这里要注意添加的位置是在 modules下的 pom.xml,也就是 test的父模块的 3、进入 test模块修改 pom.xml 把原有的system 修改成test,把 modules-system修改成

    2024年02月13日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包