【sentinel】漏桶算法在Sentinel中的应用

news2024/11/24 3:14:32

漏桶算法

漏桶算法介绍

漏桶算法,又称leaky bucket。

从图中我们可以看到,整个算法其实十分简单。首先,我们有一个固定容量的桶,有水流进来,也有水流出去。对于流进来的水来说,我们无法预计一共有多少水会流进来,也无法预计水流的速度。但是对于流出去的水来说,这个桶可以固定水流出的速率。而且,当桶满了之后,多余的水将会溢出。

我们将算法中的水换成实际应用中的请求,我们可以看到漏桶算法天生就限制了请求的速度。当使用了漏桶算法,我们可以保证接口会以一个常速速率来处理请求。所以漏桶算法天生不会出现临界问题。

漏桶算法的实现

漏桶算法具体的实现代码如下:

package com.morris.user.demo;

import lombok.extern.slf4j.Slf4j;

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 漏桶算法
 */
@Slf4j
public class LeakyBucketDemo {

    public static void main(String[] args) {
        LeakyBucket sideWindow = new LeakyBucket(2);
        for (int i = 0; i < 30; i++) {
            int finalI = i;
            new Thread(() -> {
                try {
                    TimeUnit.MILLISECONDS.sleep(new Random().nextInt(30000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info(finalI + "--> " + sideWindow.canPass());
            }).start();
        }
    }

    public static class LeakyBucket {

        // 桶的容量
        private static final long CAPACITY = 10;
        // 水漏出的速度(每秒系统能处理的请求数)
        private final long rate;
        // 当前水量(当前累积请求数)
        private double water = 0;
        // 上一次请求的时间
        private long lastRequestTime = System.currentTimeMillis();

        /**
         * @param maxCount 1秒内允许的最大请求数
         */
        public LeakyBucket(int maxCount) {
            // 每秒允许的最大请求数
            this.rate = maxCount;
        }

        public synchronized boolean canPass() {
            long now = System.currentTimeMillis();

            // 去除从lastRequestTime~now时间段应该从桶中漏出的水
            this.water = Math.max(0, water - (now - lastRequestTime) * 1.0D / 1000 * this.rate);

            this.lastRequestTime = now;

            if (this.water + 1 > CAPACITY) {
                // 桶满了
                return false;
            }
            this.water++;
            return true;
        }

    }
}

漏桶算法的实现2

漏桶算法的另一种具体实现代码如下:

package com.morris.user.demo;

import lombok.extern.slf4j.Slf4j;

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 漏桶算法
 */
@Slf4j
public class LeakyBucketDemo2 {

    public static void main(String[] args) {
        LeakyBucket sideWindow = new LeakyBucket(2);
        for (int i = 0; i < 30; i++) {
            int finalI = i;
            new Thread(() -> {
                try {
                    TimeUnit.MILLISECONDS.sleep(new Random().nextInt(3000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info(finalI + "--> " + sideWindow.canPass());
            }).start();
        }
    }

    public static class LeakyBucket {

        // 上一次请求的时间
        private long lastRequestTime = System.currentTimeMillis();
        // 两次请求之间的最小时间间隔
        private final int interval;

        public LeakyBucket(int maxCount) {
            this.interval = 1000 / maxCount;
        }

        public synchronized boolean canPass() {
            long now = System.currentTimeMillis();
            // 两次请求之间的时间间隔
            if (now - lastRequestTime >= interval) {
                lastRequestTime = now;
                return true;
            }
            return false;
        }

    }
}

漏桶算法的优缺点

优点:

  • 可以平滑限制请求的处理速度,避免瞬间请求过多导致系统崩溃或者雪崩。
  • 可以控制请求的处理速度,使得系统可以适应不同的流量需求,避免过载或者过度闲置。
  • 可以通过调整桶的大小和漏出速率来满足不同的限流需求,可以灵活地适应不同的场景。

缺点:

  • 需要对请求进行缓存,会增加服务器的内存消耗。
  • 对于流量波动比较大的场景,需要较为灵活的参数配置才能达到较好的效果。
  • 但是面对突发流量的时候,漏桶算法还是循规蹈矩地处理请求,这不是我们想看到的啦。流量变突发时,我们肯定希望系统尽量快点处理请求,提升用户体验嘛。

漏桶算法的缺点主要是由于服务和漏下来的请求之间没有交互,要么服务太忙,要么服务太闲,这就引出了令牌桶算法。

漏桶算法在sentinel中的应用

漏桶算法主要用于流控规则中流控效果为排队等待。

com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController#canPass(com.alibaba.csp.sentinel.node.Node, int, boolean)

public boolean canPass(Node node, int acquireCount, boolean prioritized) {
    // Pass when acquire count is less or equal than 0.
    if (acquireCount <= 0) {
        return true;
    }
    // Reject when count is less or equal than 0.
    // Otherwise,the costTime will be max of long and waitTime will overflow in some cases.
    if (count <= 0) {
        return false;
    }

    // 当前时间
    long currentTime = TimeUtil.currentTimeMillis();

    // 计算两个请求中间允许的时间间隔
    // Calculate the interval between every two requests.
    long costTime = Math.round(1.0 * (acquireCount) / count * 1000);

    // Expected pass time of this request.
    // 下一次请求期待的访问时间
    long expectedTime = costTime + latestPassedTime.get();

    if (expectedTime <= currentTime) {
        // 当前时间大于下一次请求期待的访问时间,允许通过
        // Contention may exist here, but it's okay.
        latestPassedTime.set(currentTime);
        return true;
    } else {
        // Calculate the time to wait.
        // 计算当前线程需要等待的时间
        long waitTime = costTime + latestPassedTime.get() - TimeUtil.currentTimeMillis();
        if (waitTime > maxQueueingTimeMs) {
            // 等待时间大于设置的最大的等待超时时间
            return false;
        } else {
            // latestPassedTime+costTime就是下一次请求期待的访问时间
            long oldTime = latestPassedTime.addAndGet(costTime);
            try {
                waitTime = oldTime - TimeUtil.currentTimeMillis();
                if (waitTime > maxQueueingTimeMs) {
                    // 说明latestPassedTime被另一个线程改了
                    // 把时间改回去,然后请求不允许通过
                    latestPassedTime.addAndGet(-costTime);
                    return false;
                }
                // in race condition waitTime may <= 0
                if (waitTime > 0) {
                    // 线程休眠,排队等待
                    Thread.sleep(waitTime);
                }
                return true;
            } catch (InterruptedException e) {
            }
        }
    }
    return false;
}

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

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

相关文章

内存池技术

为了学习池化技术以及后续自行实现一个仿tcmalloc的线程池&#xff0c;我们先浅浅的学习一下池化的概念&#xff0c;以及简单的实现一个定长的内存池。 文章目录 一&#xff1a;池化技术二&#xff1a;内存池三&#xff1a;内存池主要解决的问题四&#xff1a;malloc五&#x…

原地顺时针旋转矩阵(leetcode 48.选择图像)

本题目在leetcode上有原题48. 旋转图像 详细讲解 顺时针旋转90&#xff0c;横变竖&#xff0c;竖变横。按圈分解&#xff0c;一圈圈的单独转&#xff0c;由外圈到内圈&#xff0c;不断分解。 每一圈转到位了&#xff0c;整个矩阵就旋转好了。 那么&#xff0c;问题来了&…

Photoshop史上最强更新,动动手指就能让AI替你修图

Photoshop 在最新的 Beta 版本中&#xff0c;融入了 Firely 智能 AI 创意填充功能&#xff0c;只要对图片进行简单地框选&#xff0c;就能实现生成对象、生成背景、扩展图像、移除对象以及更多创意功能&#xff0c;支持用自然语言输入指令&#xff0c;让 AI 替你完成创意填充。…

Jmeter常用的两大性能测试场景你都知道吗?

目录 一、阶梯式场景 二、波浪式场景 一、阶梯式场景 该场景主要应用在负载测试里面&#xff0c;通过设定一定的并发线程数&#xff0c;给定加压规则&#xff0c;遵循“缓起步&#xff0c;快结束”的原则&#xff0c;不断地增加并发用户来找到系统的性能瓶颈&#xff0c;进而有…

SpringCloud:分布式缓存之Redis分片集群

1.搭建分片集群 主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决&#xff1a; 海量数据存储问题 高并发写的问题 使用分片集群可以解决上述问题&#xff0c;如图: 分片集群特征&#xff1a; 集群中有多个master&#xff0c;每个master保存不同数据 …

管道通信详解

目录 一、进程通信原理 二、什么是管道 三、创建一个匿名管道 四、fork共享管道的原理 五、管道的特点 六、4中场景 七、命名管道 八、命名管道通信的原理 九、创建一个命名管道 十、上实例 一、进程通信原理 我们知道进程间相互独立&#xff0c;具有独立性。那么我们…

编译原理 SLR(1) 语法分析器的构建

编译原理 SLR(1) 语法分析器的构建 在我的博客查看&#xff1a;https://chenhaotian.top/study/compilation-principle-slr1/ 实验三 自底向上语法分析器的构建 项目代码&#xff1a;https://github.com/chen2438/zstu-study/tree/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%8…

冈萨雷斯DIP第10章知识点

文章目录 10.2 点、线和边缘检测10.2.2 孤立点的检测10.2.3 线检测10.2.4 边缘模型 10.3 阈值处理10.3.4 使用图像平滑改进全局阈值处理10.3.5 使用边缘改进全局阈值处理10.4 使用区域生长、区域分离与聚合进行分割 分割依据的灰度值基本性质是&#xff1a;不连续性和相似性。本…

计算机网络第二章——物理层(下)

提示&#xff1a;君子可内敛不可懦弱&#xff0c;面不公可起而论之 文章目录 2.1.7 数据交换方式为什么要进行数据交换数据交换的方式电路交换电路交换的优缺点报文交换报文交换的优缺分组交换分组交换的优缺点数据交换方式的选择数据报方式虚电路方式虚电路方式的特点数据报VS…

HJ29 字符串加解密

描述 对输入的字符串进行加解密&#xff0c;并输出。 加密方法为&#xff1a; 当内容是英文字母时则用该英文字母的后一个字母替换&#xff0c;同时字母变换大小写,如字母a时则替换为B&#xff1b;字母Z时则替换为a&#xff1b; 当内容是数字时则把该数字加1&#xff0c…

深入理解设计原则之依赖反转原则(DIP)【软件架构设计】

系列文章目录 C高性能优化编程系列 深入理解软件架构设计系列 深入理解设计模式系列 高级C并发线程编程 DIP&#xff1a;依赖反转原则 系列文章目录1、依赖反转原则的定义和解读2、稳定的抽象层3、依赖倒置原则和控制反转、依赖注入的联系小结 1、依赖反转原则的定义和解读 …

多线程事务回滚方法

多线程事务回滚方法 介绍案例演示线程池配置异常类实体类控制层业务层mapper工具类验证 解决方案使用sqlSession控制手动提交事务SqlSessionTemplate注入容器中改造业务层验证成功操作示例业务层改造 介绍 1.最近有一个大数据量插入的操作入库的业务场景&#xff0c;需要先做一…

Matcher: Segment Anything with One Shot Using All-Purpose Feature Matching 论文精读

Matcher: Segment Anything with One Shot Using All-Purpose Feature Matching 论文链接&#xff1a;[2305.13310] Matcher: Segment Anything with One Shot Using All-Purpose Feature Matching (arxiv.org) 代码链接&#xff1a;aim-uofa/Matcher: Matcher: Segment Anyt…

STM32 HAL库开发——基础篇

目录 一、基础知识 1.1 Cortex--M系列介绍 1.2 什么是stm32 1.3 数据手册查看 1.4 最小系统和 IO 分配 1.4.1 电源电路 1.4.2 复位电路 1.4.3 BOOT 启动电路 1.4.4 晶振电路 1.4.5 下载调试电路 1.4.6 串口一键下载电路 1.4.7 IO 分配 1.4.8 总结 1.5 开发工…

Spring:Spring框架中的核心类 ③

一、解读思想 1、用轮廓解读体系。 2、关注细节&#xff0c;不执着细节。 二、核心类设计 1、 容器接口和实现类 ApplicationContext 接口&#xff08;容器&#xff09; ①.读取配置文件 ②.注解形成bean 哪种形式的bean统一核心管理使用中心类。 2、 ApplicationCont…

MySQL 子查询

文章目录 子查询单行子查询多行子查询相关子查询 exists 子查询 所谓子查询就是 select 查询语句中还有 select 查询语句&#xff0c;里面的称为子查询或内查询&#xff0c;外面的称为主查询或外查询。 根据查询结果记录数量&#xff0c;子查询可以分为两类&#xff1a; 单行…

机器学习 | 分类问题

目录 一、K近邻算法 二、决策树 1.一些原理介绍 2.决策树案例与实践 三、距离 一、K近邻算法 我们引入accuracy_score&#xff0c;利用score()的方法评估准确性。k近邻算法中的k是一个超参数&#xff0c;需要事先进行定义。 k值得选取经验做法是一般低于训练样本得平方根…

排书 dfs 迭代加深 IDA* 剪枝 java

&#x1f351; 算法题解专栏 &#x1f351; 排书 给定 n n n 本书&#xff0c;编号为 1 ∼ n 1 \sim n 1∼n。 在初始状态下&#xff0c;书是任意排列的。 在每一次操作中&#xff0c;可以抽取其中连续的一段&#xff0c;再把这段插入到其他某个位置。 我们的目标状态是把…

【云原生-K8s】k8s可视化管理界面安装配置及比较【Kuboard篇】

总览 安装了k8s控制面板&#xff0c;方便日常的问题处理&#xff0c;查看资源状态信息&#xff0c;也可以增加子账号进行开放给其他人员使用&#xff0c;减少命令操作&#xff0c;提升工作效率 前置条件 须有一个正常使用的k8s集群附k8s v1.23版本搭建&#xff1a;https://…

amis框架实现sdk中使用tsx

1.开发过程中&#xff0c;由于自己和同事用的不同方式使用&#xff0c;本人使用react搭建的amis框架&#xff0c;同事用sdk使用方式搭建 2.开发过程中遇到问题&#xff0c;如果需求中出现amis无法满足的组件&#xff0c;需要自己进行自定义组件&#xff0c;而不同使用方式的am…