使用令牌桶和漏桶实现请求限流逻辑

实现请求限流

  • 令牌桶算法
    • 原理
    • 实现案例
      • 案例目的:
      • 实例demo
      • 运行结果:
  • 漏桶算法
    • 原理:
    • 实现案例:
      • 案例目的:
      • 案例代码
      • 运行结果:

令牌桶算法和漏桶算法是两种常用的限流算法,用于控制系统对请求或数据的访问速率。下面分别详细解释这两种算法的原理.

令牌桶算法

原理

令牌桶算法的原理比较直观。在一个固定容量的桶中,以固定的速率持续放入令牌(token),每个令牌代表着允许通过的请求。当有请求到达时,需要获取一个令牌才能执行请求。如果没有令牌可用,请求将被限制。

实现案例

案例目的:

创建一个容量为10、速率为10个令牌/秒的令牌桶。然后循环进行20次请求,每次请求使用tryAcquire()方法尝试获取一个令牌。如果获取到令牌,则输出"Request x passed";否则输出"Request x limited"。通过设置请求的时间间隔,可以观察到令牌桶限流的效果。

实例demo

package com.mianshi;

import java.util.concurrent.TimeUnit;

/**
 * 令牌桶案例
 */
public class TokenBucket {
    private final int capacity;              // 令牌桶容量
    private final int rate;                  // 令牌生成速率(令牌/秒)
    private int tokens;                      // 当前令牌数量
    private long lastRefillTime;             // 上次填充时间

    public TokenBucket(int capacity, int rate) {
        this.capacity = capacity;
        this.rate = rate;
        this.tokens = capacity;              // 初始时令牌桶是满的
        this.lastRefillTime = System.nanoTime();
    }

    public boolean tryAcquire() {
        refillTokens();                     // 填充令牌
        System.out.println("tokens === " + tokens);
        if (tokens > 0) {
            tokens--;                       // 消费一个令牌
            return true;                    // 返回true表示允许请求通过
        } else {
            return false;                   // 返回false表示请求限制
        }
    }

    private void refillTokens() {
        long currentTime = System.nanoTime();
        System.out.println("currentTime == " + currentTime);
        long elapsedTime = currentTime - lastRefillTime;
        System.out.println("elapsedTime == " + elapsedTime);
        int generatedTokens = (int) (elapsedTime * rate / TimeUnit.SECONDS.toNanos(1));
        System.out.println("generatedTokens == " + generatedTokens);

        if (generatedTokens > 0) {
            tokens = Math.min(capacity, tokens + generatedTokens); // 补充新生成的令牌
            lastRefillTime = currentTime;                         // 更新上次填充时间
        }
        System.out.println();
    }

    public static void main(String[] args) {
        TokenBucket tokenBucket = new TokenBucket(10, 10); // 创建一个容量为10、速率为10个令牌/秒的令牌桶

        for (int i = 1; i <= 20; i++) {
            if (tokenBucket.tryAcquire()) {
                System.out.println("Request " + i + " passed"); // 请求通过
            } else {
                System.out.println("Request " + i + " limited"); // 请求被限制
            }

            try {
                Thread.sleep(100); // 模拟请求间隔时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在上述代码中,TokenBucket类实现了令牌桶算法的限流器。构造函数中传入令牌桶的容量和生成速率(令牌/秒)。tryAcquire()方法用于尝试获取一个令牌,如果成功获取到令牌则返回true,表示允许请求通过;否则返回false,表示请求被限制。

在tryAcquire()方法中,首先调用refillTokens()方法来检查是否需要填充新的令牌。然后判断当前令牌数量是否大于0,如果是,则消费一个令牌并返回true;否则返回false,表示请求被限制。

refillTokens()方法根据时间间隔和生成速率计算应该生成的新令牌数量,并将其添加到当前令牌数量中。注意,这里使用纳秒级的时间戳来进行计算。如果生成的令牌数超过了令牌桶的容量,那么令牌桶的令牌数量将被限制在容量之内。

运行结果:

...


tokens === 0
Request 16 limited
generatedTokens == 0

tokens === 0
Request 17 limited
generatedTokens == 0

tokens === 0
Request 18 limited
generatedTokens == 0

tokens === 0
Request 19 limited
generatedTokens == 0

tokens === 0
Request 20 limited

Process finished with exit code 0


漏桶算法

原理:

漏桶算法的原理是将请求或数据按照恒定的速率从容器(桶)中处理或发送出去。当请求到达时,如果当前容器有足够的空闲容量,则可以处理该请求;如果没有足够的容量,则丢弃该请求或进行排队等待处理。

实现案例:

案例目的:

创建一个容量为10、速率为10个令牌/秒的令牌桶。然后循环进行20次请求,每次请求使用tryAcquire()方法尝试获取一个令牌。如果获取到令牌,则输出"Request x passed";否则输出"Request x limited"。通过设置请求的时间间隔,可以观察到令牌桶限流的效果。

案例代码


import java.util.concurrent.TimeUnit;

/**
 * 漏桶原理
 */
public class LeakyBucket {
    private final int capacity;              // 漏桶容量
    private final int rate;                  // 处理速率(请求数/秒)
    private int waterLevel;                  // 当前水位
    private long lastLeakTime;               // 上次漏水时间

    public LeakyBucket(int capacity, int rate) {
        this.capacity = capacity;
        this.rate = rate;
        this.waterLevel = 0;                  // 初始时漏桶为空
        this.lastLeakTime = System.nanoTime();
    }

    public boolean tryConsume() {
        leakWater();                          // 漏水

        if (waterLevel < capacity) {
            waterLevel++;                     // 增加水位
            return true;                      // 返回true表示允许请求通过
        } else {
            return false;                     // 返回false表示请求被限制
        }
    }

    private void leakWater() {
        long currentTime = System.nanoTime();
        long elapsedTime = currentTime - lastLeakTime;
        int leakedRequests = (int) (elapsedTime * rate / TimeUnit.SECONDS.toNanos(1));

        if (leakedRequests > 0) {
            waterLevel = Math.max(0, waterLevel - leakedRequests); // 漏掉一定数量的请求
            lastLeakTime = currentTime;                           // 更新上次漏水时间
        }
    }

    public static void main(String[] args) {
        LeakyBucket leakyBucket = new LeakyBucket(10, 10); // 创建一个容量为10、速率为10个请求/秒的漏桶

        for (int i = 1; i <= 20; i++) {
            if (leakyBucket.tryConsume()) {
                System.out.println("Request " + i + " passed"); // 请求通过
            } else {
                System.out.println("Request " + i + " limited"); // 请求被限制
            }

            try {
                Thread.sleep(10); // 模拟请求间隔时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在上述代码中,LeakyBucket类实现了漏桶算法的限流器。构造函数中传入漏桶的容量和处理速率(请求/秒)。tryConsume()方法用于尝试消费一个请求,如果成功消费则返回true,表示允许请求通过;否则返回false,表示请求被限制。

在tryConsume()方法中,首先调用leakWater()方法来检查是否需要漏水。然后判断当前水位是否小于容器容量,如果是,则增加水位并返回true;否则返回false,表示请求被限制。

leakWater()方法根据时间间隔和处理速率计算应该漏掉的请求数量,并将其从当前水位中漏掉。注意,这里使用纳秒级的时间戳来进行计算。如果计算得到的漏掉请求数大于0,那么漏桶的水位将减去漏掉的请求数,并更新上次漏水时间。

运行结果:

在这里插入图片描述


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

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

相关文章

前端传递参数,后端如何接收

目录 简单参数 传递方式 获取方式一 获取方式二 相关注解 实体参数 数组集合参数 传递方式 相关注解 获取方式一 获取方式二 日期参数 传递方式 相关注解 获取方式 json参数 传递方式 相关注解 获取方式 路径参数 传递方式 相关注解 获取方式 传递多个…

DHCP最全讲解!(原理+配置)

一、概述 随着网络规模的不断扩大&#xff0c;网络复杂度不断提升&#xff0c;网络中的终端设备例如主机、手机、平板等&#xff0c;位置经常变化。终端设备访问网络时需要配置IP地址、网关地址、DNS服务器地址等。采用手工方式为终端配置这些参数非常低效且不够灵活。IETF于19…

day04-报表技术PDF

1 EasyPOI导出word 需求&#xff1a;使用easyPOI方式导出合同word文档 Word模板和Excel模板用法基本一致&#xff0c;支持的标签也是一致的&#xff0c;仅仅支持07版本的word也是只能生成后缀是docx的文档&#xff0c;poi对doc支持不好所以easyPOI中就没有支持doc&#xff0c…

【Linux】内核结构

一、Linux内核结构介绍 Linux内核结构框图 二、图解Linux系统架构 三、驱动认知 1、为什么要学习写驱动2、文件名与设备号3、open函数打通上层到底层硬件的详细过程 四、Shell Shell脚本 一、Linux内核结构介绍 Linux 内核是操作系统的核心部分&#xff0c;它负责管理系…

数据结构 之map/set练习

文章目录 1. 只出现一次的数字算法原理&#xff1a;代码&#xff1a; 2. 随机链表的复制算法原理&#xff1a;代码&#xff1a; 3. 宝石与石头算法原理&#xff1a;代码&#xff1a; 4. 坏键盘打字算法原理&#xff1a;代码&#xff1a; 5. 前K个高频单词算法原理&#xff1a;代…

UGUI 鼠标悬浮UI出现弹框,鼠标在图片边缘出现闪烁

1、背景&#xff1a;鼠标悬浮在UI上出现提示框 public class SpecialParam_list : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler {public void OnPointerEnter(PointerEventData eventData){TipBox.Instance.ShowBox(Input.mousePosition, value);}public void …

【从零开始学习--设计模式--代理模式】

返回首页 前言 感谢各位同学的关注与支持&#xff0c;我会一直更新此专题&#xff0c;竭尽所能整理出更为详细的内容分享给大家&#xff0c;但碍于时间及精力有限&#xff0c;代码分享较少&#xff0c;后续会把所有代码示例整理到github&#xff0c;敬请期待。 此章节介绍建…

基于中小微企业_个体工商户的信贷评分卡模型和用户画像(论文_专利_银行调研建模使用)

背景介绍 信用贷款是指由银行或其他金融机构向中小微企业和个体工商户提供的一种贷款产品。该贷款的特点是无需提供抵押品或担保&#xff0c;主要依据借款人的信用状况来进行评估和审批。 中小微企业和个体工商户信用贷款的申请流程相对简单&#xff0c;申请人只需要提供个人…

飞天使-docker知识点6-容器dockerfile各项名词解释

文章目录 docker的小技巧dockerfile容器为什么会出现启动了不暂停查看docker 网桥相关信息 docker 数据卷 docker的小技巧 [rootlight-test playbook-vars[]# docker inspect -f "{{.NetworkSettings.IPAddress}}" d3a9ae03ae5f 172.17.0.4docker d3a9ae03ae5f:/etc…

测试用例设计方法之判定表详解!!

理论部分 判定表是分析和表达多种输入条件下系统执行不同动作的工具&#xff0c;它可以把复杂的逻辑关系和多种 条件组合的情况表达得既具体又明确。 条件桩(Condition Stub)动作桩(Action Stub&#xff09;条件项(Condition Entry&#xff09;动作项(Action Entry&#xff0…

python+requests+pytest 接口自动化实现

最近工作之余拿公司的项目写了一个接口测试框架&#xff0c;功能还不是很完善&#xff0c;算是抛砖引玉了&#xff0c;欢迎各位来吐槽。 主要思路&#xff1a; ①对 requests 进行二次封装&#xff0c;做到定制化效果 ②使用 excel 存放接口请求数据&#xff0c;作为数据驱动 ③…

配电房环境监测模块

配电房环境监测模块是一个智能系统&#xff0c;依托电易云-智慧电力物联网平台&#xff0c;旨在实时监控配电房内部的环境参数&#xff0c;以确保配电设备的正常运行。该模块包括以下功能&#xff1a; 温度监测&#xff1a;对配电房内的温度进行实时监测&#xff0c;防止因温度…

CSS 基础

文章目录 CSS 常见的属性CSS 常见样式行内样式内嵌样式导入样式 CSS 选择器标签选择器id选择器类选择器全局选择器属性选择器组合选择器 CSS 常见应用表格列表导航栏下拉菜单提示工具图片廊 CSS (Cascading Style Sheets&#xff0c;层叠样式表&#xff09;&#xff0c;是一种用…

Pytorch当中的.detach()操作是什么意思

.detach() 是 PyTorch 中用于从计算图中分离张量的方法。当我们在PyTorch中进行张量运算时&#xff0c;操作会构建一个计算图来跟踪计算历史&#xff0c;这个计算图用于自动求导和反向传播来计算梯度。 使用.detach()方法可以将一个张量从当前的计算图中分离出来&#xff0c;使…

【C语言】动态内存管理(C语言的难点与精华,数据结构的前置知识,你真的掌握了吗?)

文章目录 引言一、为什么要动态内存分配二、动态内存分配的相关函数2.1 malloc2.2 free2.3 calloc2.4 realloc 三、常见的动态内存的错误3.1 对NULL指针的解引用3.2 对动态内存越界访问3.3 对非动态内存释放3.4 对动态内存部分释放3.5 对动态内存多次释放3.6 未对动态内存释放&…

Unity中Shader URP的安装与设置

文章目录 前言一、URP安装1、Window -> Project Manager -> 搜索 Render 二、URP设置1、创建一个URP配置文件2、渲染管线的修改&#xff08;当为空时&#xff0c;使用的是 BuildIn Render Pipeline&#xff09;3、这时我们新建一个对象。使用的材质球默认使用 URP 默认Sh…

【JAVA面向对象练习】---第四天

数据求和类 定义一个类Demo,其中定义一个求两个数据和的方法&#xff0c;定义一个测试了Test&#xff0c;进行测试。 package com.fuhai.day04;public class Sum {private double a;private double b;public double getA() {return a;}public void setA(double a) {this.a a…

AE-制作绚丽的图形通道

目录 1.新建合成命名为四边形 2.在合成中新建纯色层命名为tao 3.在纯色层上添加RG Trapcode –>Tao 效果&#xff0c;设置Segment参数 4. 在合成中添加摄像机 5.设置Tao Repeat Paths 相关参数&#xff0c;并调整摄像机的位置 6.设置Tao的 Material & Lighting 等…

系列一、Linux中安装MySQL

一、Linux中安装MySQL 1.1、下载MySQL安装包 官网&#xff1a;https://dev.mysql.com/downloads/file/?id523327 我分享的&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/188_9RnBYlWVzFb_UJH5aaQ?pwdyyds 提取码&#xff1a;yyds 1.2、上传至/opt目录 & 解压…

【每日一题】统计区间中的整数数目

文章目录 Tag题目来源解题思路方法一&#xff1a;平衡二叉搜索树 写在最后 Tag 【平衡二叉搜索树】【设计类】【2023-12-16】 题目来源 2276. 统计区间中的整数数目 解题思路 方法一&#xff1a;平衡二叉搜索树 思路 用一棵平衡二叉搜索树维护插入的区间&#xff0c;树中的…