常见四种限流算法详解(附:javaDemo)

限流简介

现代互联网很多业务场景,比如秒杀、下单、查询商品详情,最大特点就是高并发,而往往我们的系统不能承受这么大的流量,继而产生了很多的应对措施:CDN、消息队列、多级缓存、异地多活。

但是无论如何优化,终究由硬件的物理特性决定了我们系统性能的上限,如果强行接收所有请求,往往造成雪崩。

这时候限流熔断就发挥作用了,限制请求数,快速失败,保证系统满负载又不超限。

极致的优化,就是将硬件使用率提高到100%,但永远不会超过100%

计数器法

计数器法是限流算法里最简单也是最容易实现的一种算法。比如我们规定,对于A接口来说,我们1秒钟的访问次数 不能超过100次。那么我们可以这么做:在一开始的时候,我们可以设置一个计数器counter,每当一个请求过来的 时候,counter就加1,如果counter的值大于100并且该请求与第一个请求的间隔时间还在1秒钟之内,那么说明请 求数过多;如果该请求与第一个请求的间隔时间大于1秒钟,且counter的值还在限流范围内,那么就重置 counter。

 

 具体算法的伪代码:

/**
 * 计数器限流算法
 */
public class CounterLimiter {
    private long timeStamp = System.currentTimeMillis();
    private int reqCount; // 请求次数
    private int limitNum = 10; // 每秒限流的最大请求数
    private long interval = 3000L; // 时间窗口时长,单位ms

    /**
     * @return 返回true代表限流,false代表通过
     */
    public synchronized Boolean limit() {
        long now = System.currentTimeMillis();
        if (now < timeStamp + interval) { // 在当前时间窗口内
        // 判断当前时间窗口请求数加1是否超过每秒限流的最大请求数
            if (reqCount + 1 > limitNum) {
                return true;
            }
            reqCount++;
            return false;
        } else { //开启新的时间窗口
            timeStamp = now;
        // 重置计数器
            reqCount = 1;
            return false;
        }
    }
}

滑动时间窗口算法

滑动时间窗口,又称rolling window。为了解决计数器法统计精度太低的问题,引入了滑动窗口算法。下面这张 图,很好地解释了滑动窗口算法:

在上图中,整个红色的矩形框表示一个时间窗口,在我们的例子中,一个时间窗口就是一秒钟。然后我们将时间窗 口进行划分,比如图中,我们就将滑动窗口划成了10格,所以每格代表的是100毫秒。每过100毫秒,我们的时间 窗口就会往右滑动一格。我们会根据请求发生的时间找到对应的时间窗格,然后在窗格里维护一个计数器 counter,并让其加1,比如当一个请求在550毫秒的时候到达,那么500-600毫秒对应窗格里的counter就会加1。 计数器算法其实就是滑动窗口算法。只是它没有对时间窗口做进一步地划分,所以只有1个窗格。 由此可见,当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精确。

具体算法的伪代码:

/**
 * 滑动时间窗口限流实现
 * 假设某个服务最多只能每秒钟处理100个请求,我们可以设置一个1秒钟的滑动时间窗口,
 * 窗口中有10个格子,每个格子100毫秒,每100毫秒移动一次格子,每个格子记录当前100毫秒内的请求次数
 */
public class SlidingTimeWindowLimiter {

    // 统计周期 1000ms
    public static final int TIME_WINDOW = 1000;

    private static final LinkedList<Long> list = new LinkedList<>();

    // 时间窗口内允许的最大请求数
    private final int maxCount;

    public SlidingTimeWindowLimiter(int maxCount) {
        this.maxCount = maxCount;
    }

    public synchronized boolean limit() {
        // 获取当前时间
        long nowTime = System.currentTimeMillis();
        // 如果队列还没满,则允许通过,并添加当前时间戳到队列开始位置
        if (list.size() < maxCount) {
            list.addFirst(nowTime);
            return true;
        }

        // 队列已满(达到限制次数),则获取队列中最早添加的时间戳
        Long farTime = list.getLast();
        // 用当前时间戳 减去 最早添加的时间戳
        if (nowTime - farTime <= TIME_WINDOW) {
            // 若结果小于等于timeWindow,则说明在timeWindow内,通过的次数大于count
            // 不允许通过
            return false;
        } else {
            // 若结果大于timeWindow,则说明在timeWindow内,通过的次数小于等于count
            // 允许通过,并删除最早添加的时间戳,将当前时间添加到队列开始位置(开始滑动)
            list.removeLast();
            list.addFirst(nowTime);
            return true;
        }
    }
}

漏桶算法

漏桶算法,又称leaky bucket。

从图中我们可以看到,整个算法其实十分简单。首先,我们有一个固定容量的桶,有水流进来,也有水流出去。对 于流进来的水来说,我们无法预计一共有多少水会流进来,也无法预计水流的速度。但是对于流出去的水来说,这 个桶可以固定水流出的速率。而且,当桶满了之后,多余的水将会溢出。 我们将算法中的水换成实际应用中的请求,我们可以看到漏桶算法天生就限制了请求的速度。当使用了漏桶算法, 我们可以保证接口会以一个常速速率来处理请求。所以漏桶算法天生不会出现临界问题。

具体的伪代码如下: 

/**
 * 漏桶限流算法
 */
public class LeakyBucketLimiter {
    /**
     * 桶的容量
     */
    private final long capacity = 20L;

    /**
     * 水流出的数量速度
     */
    private final long rate = 10L;
    /**
     * 水流出的时间速度
     */
    private final long rateTime = 1000L;

    /**
     * 当前水量(实际上就是请求数)
     */
    private long water = 0L;

    /**
     * 上次漏水时间
     */
    private long lastTime = System.currentTimeMillis();

    public synchronized boolean limit() {
        long now = System.currentTimeMillis();
        //计算当前水量
        long distance = now - lastTime;
        water = Math.max(0, water - (distance / rateTime) * rate);
        lastTime = now;
        //判断剩余空间是否足够
        if ((water + 1) < capacity) {
            water++;
            return true;
        } else {
            return false;
        }
    }

}

令牌桶算法

令牌桶算法,又称token bucket。同样为了理解该算法,我们来看一下该算法的示意图:

从图中我们可以看到,令牌桶算法比漏桶算法稍显复杂。首先,我们有一个固定容量的桶,桶里存放着令牌 (token)。桶一开始是空的,token以 一个固定的速率r往桶里填充,直到达到桶的容量,多余的令牌将会被丢 弃。每当一个请求过来时,就会尝试从桶里移除一个令牌,如果没有令牌的话,请求无法通过。

具体的伪代码如下: 

/**
 * 令牌桶限流算法
 */
public class TokenBucketLimiter{
    private long lastTime = System.currentTimeMillis();
    /**
     * 桶的容量
     */
    private long capacity = 40;
    /**
     * 当前令牌数量
     */
    private long tokens = 0;
    /**
     * 令牌放入数量速度
     */
    private long rate = 10;
    /**
     * 令牌放入时间速度
     */
    private final long rateTime = 1000L;
    
    /**
     * @return 返回true代表限流,false代表通过
     */
    public synchronized Boolean limit() {
        long now = System.currentTimeMillis();
        // 先添加令牌
        // 计算当前令牌数,令牌数最大为桶的容量
        long distance = now - lastTime;
        tokens = Math.min(capacity, tokens + distance * rate/ rateTime);

        lastTime = now;
        if (tokens < 1) {
            // 若不到1个令牌,则拒绝
            return true;
        } else {
            // 还有令牌,领取令牌
            tokens--;
            return false;
        }
    }
}

限流算法小结

计数器 VS 滑动窗口

1 计数器算法是最简单的算法,可以看成是滑动窗口的低精度实现。

2 滑动窗口由于需要存储多份的计数器(每一个格子存一份),所以滑动窗口在实现上需要更多的存储空间。

3 也就是说,如果滑动窗口的精度越高,需要的存储空间就越大。

漏桶算法 VS 令牌桶算法

1 漏桶算法和令牌桶算法最明显的区别是令牌桶算法允许流量一定程度的突发。

2 因为默认的令牌桶算法,取走token是不需要耗费时间的,也就是说,假设桶内有100个token时,那么可以瞬间允许100个请求通过。

3 当然我们需要具体情况具体分析,只有最合适的算法,没有最优的算法

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

今日学习总结2024.3.2

最近的学习状态比较好&#xff0c;感觉非常享受知识进入脑子的过程&#xff0c;有点上头。 实验室一个星期唯一一天的假期周六&#xff0c;也就是今天&#xff0c;也完全不想放假出去玩啊&#xff0c;在实验室泡了一天。 很后悔之前胆小&#xff0c;没有提前投简历找实习&…

基于毕奥-萨伐尔定律的交流电机的4极旋转磁场matlab模拟与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于毕奥-萨伐尔定律的交流电机的4极旋转磁场&#xff0c;对比不同定子半径&#xff0c;对比2级旋转磁场。 2.系统仿真结果 3.核心程序与模型 版本&#xff1a;MATLAB2022a…

UE5数字孪生系列笔记(一)

智慧城市数字孪生系统 虚幻引擎连接数据库 将自己的mysql版本的libmysql.dll替换掉插件里面的libmysql.dll 然后将这个插件目录复制到虚幻项目目录下 然后添加这个插件即可 新建一个UMG&#xff0c;添加一个按钮试试&#xff0c;数据库是否连接 将UI添加到视口 打印是否连接…

ChaosBlade故障注入工具--cpu,内存,磁盘占用\IO,网络注入等

前言&#xff1a; 本文介绍一款开源的故障注入工具chaosblade&#xff0c;该工具原本由阿里研发&#xff0c;现已开源&#xff1b;工具特点&#xff1a;功能强大&#xff0c;使用简单。 该工具故障注入包含&#xff1a;cpu&#xff0c;内存&#xff0c;磁盘io&#xff0c;磁盘…

第一讲 计算机组成与结构(初稿)

计算机组成与结构 计算机指令常见CPU寄存器类型有哪些&#xff1f;存储器分类&#xff1f;内存&#xff1f;存储器基本组成&#xff1a; 控制器的基本组成主机完成指令的过程以取数指令为例以存数指令为例ax^2bxc程序的运行过程 机器字长存储容量小试牛刀&#xff08;答案及解析…

Chapter20-Ideal gases-CIE课本要点摘录、总结(编辑中)

20.1 Particles of a gas Brownian motion Fast modules 速率的数值大概了解下&#xff1a; average speed of the molecules:400m/s speed of sound:approximately 330m/s at STP&#xff08;standard temperature and pressure&#xff09; Standard Temperature and Pres…

【论文阅读】(2024.03.05-2024.03.15)论文阅读简单记录和汇总

(2024.03.05-2024.03.15)论文阅读简单记录和汇总 2024/03/05&#xff1a;随便简单写写&#xff0c;以后不会把太详细的记录在CSDN&#xff0c;有道的Markdown又感觉不好用。 目录 &#xff08;ICMM 2024&#xff09;Quality Scalable Video Coding Based on Neural Represent…

JAVA开发第一个Springboot WebApi项目

一、创建项目 1、用IDEA新建一个SpringBoot项目 注意JDK与Java版本的匹配,如果想选择jdk低版本,先要更改服务器URL:start.aliyun.com 2、添加依赖 (1)、Lombok (2)、Spring Web (3)、Mybatis Framework (4)、MySqlDriver 项目中的配置 pom.xml 如下 <?…

Jellyfin影音站点搭建并结合内网穿透实现远程观看本地影视资源

文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及&#xff0c;各种各样的使用需求也被开发出来&…

LeetCode每日一题之 快乐数

目录 题目介绍&#xff1a; 算法原理&#xff1a; 鸽巢原理&#xff1a; 如何找到环里元素&#xff1a; 代码实现&#xff1a; 题目介绍&#xff1a; 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 算法原理&#xff1a; 我先简单举两个例子&#xff…

让照片说话唱歌的软件,盘点这3款!

在数字时代&#xff0c;我们总是渴望找到新的方式来表达自我、分享生活。近年来&#xff0c;随着人工智能和图像处理技术的飞速发展&#xff0c;一种新型的软件应运而生&#xff0c;它们能够让照片“说话”甚至“唱歌”&#xff0c;给我们的生活带来了无限乐趣和创意空间。那么…

光线追踪10 - Dielectrics( 电介质 )

水、玻璃和钻石等透明物质都属于电介质。当光线射入这些物质时&#xff0c;会分为反射光线和折射&#xff08;透射&#xff09;光线。我们将通过随机选择反射或折射来处理这一现象&#xff0c;每次相互作用只生成一条散射光线。11.1 Refraction 最难调试的部分是折射光线。通常…

SpringBoot 热部署。

SpringBoot 热部署。 文章目录 SpringBoot 热部署。 pom.xml。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional…

.Net利用Microsoft.Extensions.DependencyInjection配置依赖注入

一、概述 为了让接口程序更加模块化和可测试&#xff0c;采用依赖注入的方式调用接口方法。 二、安装Microsoft.Extensions.DependencyInjection 在NuGet里面搜索Microsoft.Extensions.DependencyInjection&#xff0c;并进行安装。 三、代码编写 3.1 创建Service 实现类…

SpringMVC-异步调用,拦截器与异常处理

1.异步调用 1.发送异步请求 <a href"javascript:void(0);" id"testAjax">访问controller</a> <script type"text/javascript" src"js/jquery-3.7.1.js"></script> <script type"text/javascript&qu…

mysql 数据库查询 查询字段用逗号隔开 关联另一个表并显示

文章目录 问题描述解决方案 问题描述 如下如所示&#xff1a; 表一&#xff1a;wechat_dynamically_config表&#xff0c;重点字段&#xff1a;wechat_object 表二&#xff1a;wechat_object表&#xff0c;重点字段&#xff1a;wxid 需求&#xff1a;根据wechat_dynamically_…

你不知道的Postman的Mock接口测试,看这一篇就够了

前言 创建Mock服务 你可以从Postman已有的测试集(Collection)中创建Mock Server或者直接创建Mock Server&#xff08;我们这里选择从已有的测试集中创建Mock Server&#xff09; Mock server详细配置页面&#xff0c;在此页面中我们可以设置&#xff1a; Name the mock serv…

JOSEF约瑟 同步检查继电器 BT-1B/R200 额定电压100/100V, 直流电压220V

BT-1B/R型同步检查继电器型号&#xff1a; BT-1B型同步检查继电器&#xff1b; BT-1B/R200同步检查继电器; BT-1B/R160同步检查继电器; BT-1B/R130同步检查继电器; BT-1B/R120同步检查继电器; BT -1B/R90同步检查继电器; 用途 BT-1B/R型同步检查继电器用于两端供电系统…

小程序应用为亲子陪伴趣味赋能

导言&#xff1a; 在现代社会&#xff0c;随着工作压力的增加和生活节奏的加快&#xff0c;家长们往往面临着亲子陪伴不足的困扰。而小程序应用的普及&#xff0c;为家庭提供了更多的亲子活动选择和参与方式。虎克技术公司成功帮助客户通过开发小程序实现亲子陪伴的赋能&#x…

北斗卫星助力无人机在沙漠播种,促进沙漠治理

北斗卫星助力无人机在沙漠播种&#xff0c;促进沙漠治理 近年来&#xff0c;随着科技的不断发展&#xff0c;北斗卫星和无人机技术的结合被广泛应用于沙漠治理领域&#xff0c;为解决沙漠化问题提供了全新的思路和解决方案。 近日&#xff0c;黄河“几字弯”北岸的内蒙古自治…