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

news2024/12/23 14:17:40

实现请求限流

  • 令牌桶算法
    • 原理
    • 实现案例
      • 案例目的:
      • 实例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.coloradmin.cn/o/1322655.html

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

相关文章

二进制枚举算法

二进制 : 也就是只有0和1的进制表示 ; 二进制枚举算法 一个二进制数 x 可以表示 S 的一个子集&#xff0c;某个二进制位i上为0表示没有选i元素&#xff0c;为1表示选了该元素放入子集,比如13为1101就表示选了0,2,3号元素;对于一个长度为N的序列(也就是包含N个元素)有2^N个子…

深入理解PyTorch中的Hook机制:特征可视化的重要工具与实践

文章目录 一、前言1. 特征可视化的重要性2. PyTorch中的hook机制简介 二、Hook函数概述1. Tensor级别的hook&#xff1a;register_hook()2. Module级别的hook 三、register_forward_hook()详解1. 功能与使用场景2. 示例代码与解释3. 在特征可视化中的具体应用 四、register_bac…

数据结构--图(更新ing~)

树具有灵活性&#xff0c;并且存在许多不同的树的应用&#xff0c;但是就树本身而言有一定的局限性&#xff0c;树只能表示层次关系&#xff0c;比如父子关系。而其他的比如兄弟关系只能够间接表示。 推广--- 图 图形结构中&#xff0c;数据元素之间的关系是任意的。 一、图…

C语言快速排序算法以及代码

接下来我们将用图像模拟来一步步演示快速排序的过程&#xff0c;这样我们将会通过视觉和大脑一起来梳理快速排序的思路。 后文示例的C语言代码将实现图像模拟的过程。 一、图像模拟 快速排序 过程 我们选取十个数字0~9当做我们的排序数字&#xff0c;并将其打乱。然后我们将…

Axure的交互以及情形的介绍

一. 交互 1.1 交互概述 通俗来讲就是&#xff0c;谁用了什么方法做了什么事情&#xff0c;主体"谁"对应的就是axure中的元件&#xff0c;"什么方法"对应的就是交互事件&#xff0c;比如单击事件、双击事件&#xff0c;"什么事情"对应的就是交互…

银河麒麟v10 安装mysql 8.35

银河麒麟v10 安装mysql 8.35 1、下载Mysql安装包2、安装Mysql 8.352.1、安装依赖包2.2、安装Mysql2.3、安装后配置 1、下载Mysql安装包 访问官网下载链接 链接: https://dev.mysql.com/downloads/mysql/ 选择如下 点击下载按钮 下载安装包 2、安装Mysql 8.35 官方安装文档…

挑战52天学小猪佩奇笔记--day25

52天学完小猪佩奇--day25 ​【本文说明】 本文内容来源于对B站UP 脑洞部长 的系列视频 挑战52天背完小猪佩奇----day25 的视频内容总结&#xff0c;方便复习。强烈建议大家去关注一波UP&#xff0c;配合UP视频学习。 day25的主题&#xff1a;生病了 猜台词&#xff1a; Daddy: …

我勒个豆,怎么没人告诉我这个偷懒神器啊

OMG&#xff0c;还有行政人不知道它的吗&#xff1f;&#xff1f;再不用真的亏大了啊&#xff01;&#xff01; 这东西写啥都可以&#xff0c;只有输入需求马上就写好了啊&#xff0c;什么工作总结&#xff0c;活动策划方案&#xff0c;会议纪要啥啥都可以&#xff0c;全能写啊…

持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布

目录 一、实验 1.环境 2.GitLab 更新deployment文件 3.GitLab更新共享库前端项目CI与CD流水线 4.K8S查看前端项目版本 5.Jenkins 构建前端项目 6.Jenkins 再次构建前端项目 二、问题 1. Jenkins 构建CI 流水线报错 2. Jenkins 构建CI 流水线弹出脚本报错 3. Jenkins…

长短期记忆(LSTM)神经网络-多输入分类

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、部分程序&#xff1a; 四、完整程序下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matlab平台编译&am…

Linux-----17、软件包管理

# 软件包管理 # 1、软件包分类 # ㈠ 软件包类型 二进制包源码包 # ① 二进制包 什么是二进制包&#xff1f;有什么特点&#xff1f; 二进制包&#xff0c;指的是已经 1 好了的软件包&#xff0c;只需要直接安装就可以使用。二进制包&#xff0c;不需要编译&#xff0c;直接…

【人工智能革命】:AIGC时代的到来 | 探索AI生成内容的未来

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; IT杂谈 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. AIGC 技术的概述和发展趋势1.1 AIGC 技术的概述1.2 AIGC 技术的发展趋势 二. AIGC 与元宇…

Java-基础部分(二)

一、抽象类 当编写一个类时&#xff0c;我们往往会为该类定义一些方法&#xff0c;这些方法是用来描述该类的行为方式&#xff0c;那么这些方法都有具体的方法体。 分析事物时&#xff0c;发现了共性内容&#xff0c;就出现向上抽取。会有这样一种特殊情况&#xff0c;就是功…

使用 React 实现自定义数据展示日历组件

目录 背景实现日历组件父组件数据 效果最后 背景 项目中需要实现一个日历组件&#xff0c;并且需要展示月&#xff0c;日所对应的数据&#xff08;因为项目需求问题&#xff0c;就不统计年数据总量&#xff09;。网上找了一堆&#xff0c;基本都不大符合项目需求&#xff0c;且…

计算机提示由于找不到vcruntime140_1.dll怎么办,那种修复方法推荐

首先&#xff0c;让我们来了解一下vcruntime140_1.dll是什么。其实&#xff0c;vcruntime140_1.dll是Visual C Redistributable Packages的一部分&#xff0c;它是由Microsoft Visual Studio编写的程序运行时库。它包含了许多用于运行Windows应用程序的函数和资源。因此&#x…

VueStu02-创建一个Vue实例

一、核心步骤 1.准备容器 准备一个盒子div。 2.引包 从官网引包&#xff0c;有开发版本和生产版本之分。 3.创建Vue实例 创建一个Vue实例&#xff0c;new Vue()。 4.指定配置项 指定配置项&#xff0c;用于渲染数据 。 el&#xff1a;指定挂载点。知道自己将来要管理的是…

Python实验作业,爬虫,中国院士信息

实验内容&#xff1a; 爬取中国工程院网页上&#xff0c;把每位院士的简介保存为本地文本文件&#xff0c;把每位院士的照片保存为本地图片&#xff0c;文本文件和图片文件都以院士的姓名为主文件名。 实验代码&#xff1a; import os.path import time from urllib.request …

干货教学!!!RHEL8中ansible中常用模块的使用

内容很长各位大老爷耐心观看 本章主要介绍ansible中最常见模块的使用 文件管理模块软件包管理模块服务管理模块磁盘管理模块用户管理模块防火墙管理模块 ansible的基本用法如下 ansible 机器名 -m 模块x -a “模块的参数” 对被管理机器执行不同的操作&#xff0c;只需要调…

git修改远程commit信息

git 修改远程commit信息 如果你已经把本地commit的信息push到远程了&#xff0c;此时需要修改远程中的commit信息 第一步&#xff1a;git log 查看提交的信息,看下提交的commit日志 如下入所示 第二步&#xff1a;然后确定你需要修改的那一次commit&#xff0c;比如&#xf…

LeetCode Hot100 51.N皇后

题目&#xff1a; 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的…