当前位置: 首页 > article >正文

常见限流算法及实现

1. 固定窗口计数器(Fixed Window Counter)

  • 原理:在固定时间窗口(如1分钟)内统计请求数,超过阈值则拒绝后续请求。
  • 优点:实现简单,内存占用低。
  • 缺点:存在窗口切换时的流量突增问题(如相邻窗口边界处可能允许双倍流量)。
/*** @description: 固定窗口限流* @Author: whopxx* @CreateTime: 2025-03-16*/
public class FixedWindowLimiter {private final int limit;      // 窗口内最大请求数private final long windowMs;  // 窗口时间(毫秒)private final AtomicInteger counter = new AtomicInteger(0);private volatile long windowStart = System.currentTimeMillis();public FixedWindowLimiter(int limit, long windowMs) {this.limit = limit;this.windowMs = windowMs;}public boolean tryAcquire() {long now = System.currentTimeMillis();if (now - windowStart > windowMs) {synchronized (this) {if (now - windowStart > windowMs) {windowStart = now;counter.set(0);}}}return counter.incrementAndGet() <= limit;}public static void main(String[] args) {FixedWindowLimiter fixedWindowLimiter = new FixedWindowLimiter(5, 1000);for (int i = 0; i < 100; i++) {boolean b = fixedWindowLimiter.tryAcquire();System.out.println(b);try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

2. 滑动窗口计数器(Sliding Window Counter)

  • 原理:将时间分割为更细粒度的子窗口(如每分钟分为60个1秒窗口),统计最近完整时间窗口内的请求总数。
  • 优点:缓解固定窗口的临界问题,限流更平滑。
  • 缺点:实现较复杂,需存储子窗口的请求记录。
/*** @description: 滑动窗口限流* @Author: whopxx* @CreateTime: 2025-03-16*/
public class SlidingWindowLimiter {private final long windowMs;          // 窗口总时间(毫秒)private final int subWindowCount;     // 子窗口数量private final long subWindowMs;       // 子窗口时间(毫秒)private final int limit;              // 窗口内最大请求数private final AtomicInteger[] counters;private final long[] windowStartTimes; // 每个子窗口的起始时间private final ReentrantLock lock = new ReentrantLock();public SlidingWindowLimiter(int limit, long windowMs, int subWindowCount) {this.limit = limit;this.windowMs = windowMs;this.subWindowCount = subWindowCount;this.subWindowMs = windowMs / subWindowCount;this.counters = new AtomicInteger[subWindowCount];this.windowStartTimes = new long[subWindowCount];for (int i = 0; i < subWindowCount; i++) {counters[i] = new AtomicInteger(0);windowStartTimes[i] = System.currentTimeMillis() - i * subWindowMs;}}public boolean tryAcquire() {long now = System.currentTimeMillis();lock.lock();try {// 1. 清理所有过期的子窗口int expiredCount = 0;for (int i = 0; i < subWindowCount; i++) {if (now - windowStartTimes[i] > windowMs) {expiredCount += counters[i].getAndSet(0);windowStartTimes[i] = now - (now % subWindowMs); // 对齐时间窗口}}// 2. 计算当前子窗口索引int currentSubIdx = (int) ((now % windowMs) / subWindowMs);// 3. 统计当前窗口内总请求数int total = expiredCount;for (int i = 0; i < subWindowCount; i++) {total += counters[i].get();}if (total >= limit) {return false;}// 4. 写入当前子窗口counters[currentSubIdx].incrementAndGet();return true;} finally {lock.unlock();}}public static void main(String[] args) throws InterruptedException {// 测试:限制1秒内最多2次请求,窗口分为5个子窗口(每个200ms)SlidingWindowLimiter limiter = new SlidingWindowLimiter(2, 1000, 5);for (int i = 0; i < 10; i++) {System.out.println("Request " + (i + 1) + ": " + (limiter.tryAcquire() ? "OK" : "Limited"));Thread.sleep(150); // 模拟请求间隔150ms}}
}

3. 漏桶算法(Leaky Bucket)

  • 原理:请求像水一样进入桶中,桶以固定速率“漏水”(处理请求),桶满则拒绝新请求。
  • 优点:强制恒定速率处理,适合平滑突发流量。
  • 缺点:无法灵活应对突发流量(即使系统空闲时也无法瞬时处理大量请求)。
/*** @description: 漏桶限流器* @Author: whopxx* @CreateTime: 2025-03-16*/
public class LeakyBucketLimiter {private final long capacity;     // 桶容量private final long rate;         // 流出速率,每秒rate个private AtomicLong water = new AtomicLong(0);          // 当前水量private long lastLeakTime = System.currentTimeMillis();public LeakyBucketLimiter(long capacity, long rateMsPerReq) {this.capacity = capacity;this.rate = rateMsPerReq;}public synchronized boolean tryAcquire() {if (water.get() == 0){lastLeakTime = System.currentTimeMillis();water.set(1);return true;}water.set(water.get() - (System.currentTimeMillis() - lastLeakTime) / 1000 * rate);water.set(water.get() < 0 ? 0 : water.get());lastLeakTime += (System.currentTimeMillis() - lastLeakTime) / 1000 * 1000;if (water.get() >= capacity) {return false;} else {water.set(water.get() + 1);return true;}}public static void main(String[] args) {LeakyBucketLimiter limiter = new LeakyBucketLimiter(5, 1); // 容量为5,流出速率为1个/秒for (int i = 0; i < 100; i++) {boolean b = limiter.tryAcquire();System.out.println(b);try {Thread.sleep(200);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

4. 令牌桶算法(Token Bucket)

  • 原理:系统以固定速率生成令牌存入桶,请求需获取令牌才能处理,无令牌时触发限流。
  • 优点:允许突发流量(桶内积累的令牌可一次性使用),更灵活。
  • 缺点:需维护令牌生成逻辑,实现较复杂。
  • 典型应用:Guava的RateLimiter、Nginx限流模块。
/*** @description: 令牌桶限流算法* @Author: whopxx* @CreateTime: 2025-03-16*/
public class TokenBucketLimiter {//桶的容量private final long capacity;//放入令牌的速率 每秒放入的个数private final long rate;//上次放置令牌的时间private static long lastTime = System.currentTimeMillis();//桶中令牌的余量private static AtomicLong tokenNum = new AtomicLong();public TokenBucketLimiter(int capacity, int permitsPerSecond) {this.capacity = capacity;this.rate = permitsPerSecond;tokenNum.set(capacity);}public synchronized  boolean tryAcquire() {//更新桶中剩余令牌的数量long now = System.currentTimeMillis();tokenNum.addAndGet((now - lastTime) / 1000 * rate);tokenNum.set(Math.min(capacity, tokenNum.get()));//更新时间lastTime += (now - lastTime) / 1000 * 1000;//桶中还有令牌就放行if (tokenNum.get() > 0) {tokenNum.decrementAndGet();return true;} else {return false;}}//测试public static void main(String[] args) {TokenBucketLimiter limiter = new TokenBucketLimiter(3, 2); // 允许每秒放入2个令牌,桶容量为5for (int i = 0; i < 100; i++) {if (limiter.tryAcquire()) {System.out.println("成功请求");} else {System.out.println("请求失败");}try {Thread.sleep(300); // 模拟请求间隔} catch (InterruptedException e) {e.printStackTrace();}}}
}


对比总结

方式

适用场景

固定窗口

简单低频场景

滑动窗口

需平滑限流的场景

漏桶算法

恒定速率处理(如流量整形)

令牌桶算法

允许突发的场景(如秒杀)

相关文章:

常见限流算法及实现

1. 固定窗口计数器&#xff08;Fixed Window Counter&#xff09; 原理&#xff1a;在固定时间窗口&#xff08;如1分钟&#xff09;内统计请求数&#xff0c;超过阈值则拒绝后续请求。优点&#xff1a;实现简单&#xff0c;内存占用低。缺点&#xff1a;存在窗口切换时的流量…...

计算机操作系统进程(4)

系列文章目录 第二章&#xff1a;进程的描述与控制 文章目录 系列文章目录前言一、临界区的概念和描述&#xff1a;二、硬件同步机制&#xff1a; 1.关中断2.利用Test-and-Set指令实现互斥3.利用Swap指令实现进程的互斥 总结 前言 上一篇我们仅仅讲了一点关于线程同步的概念&a…...

编程题《牛牛的链表删除》的python可以用非链表的方式

描述 牛牛从键盘输入了一个长度为 n 的数组&#xff0c;把这个数组转换成链表然后把链表中所有值是 x 的节点都删除。 输入描述&#xff1a; 第一行输入两个正整数 n 和 x 表示数组的长度和要删除的链表节点值 x 。 第二行输入 n 个正整数表示数组中每个元素的值。 输出描述&am…...

Certbot实现SSL免费证书自动续签(CentOS 7版 + Docker部署的nginx)

前置安装&#xff0c;可参考Certbot实现SSL免费证书自动续签&#xff08;CentOS 7 nginx/apache&#xff09; 如果是通过 Docker 运行 Nginx&#xff0c; certbot 无法直接检测到本地的 Nginx 配置。解决方案是 使用 standalone 模式 或 挂载 Webroot 方式获取 SSL 证书&…...

C++|构造函数和析构函数

一、构造函数 构造函数是一种特殊的成员函数&#xff0c;主要用于创建对象时对对象进行初始化操作&#xff0c;即专门用于构造新对象&#xff0c;并赋值对象的成员数据。 在 C 里&#xff0c;构造函数的名称和类名相同&#xff0c;并且没有返回类型。当创建类的对象时&#x…...

AI日报 - 2025年3月17日

&#x1f31f; 今日概览&#xff08;60秒速览&#xff09; ▎&#x1f916; AGI突破 | GPT-o1在卡内基梅隆大学数学考试中获满分&#xff0c;展示AI数学能力新高度 成本仅5美分/题&#xff0c;推理速度不到1分钟 ▎&#x1f4bc; 商业动向 | Figure推出BotQ机器人制造设施&…...

不像人做的题————十四届蓝桥杯省赛真题解析(上)A,B,C,D题解析

题目A&#xff1a;日期统计 思路分析&#xff1a; 本题的题目比较繁琐&#xff0c;我们采用暴力加DFS剪枝的方式去做&#xff0c;我们在DFS中按照8位日期的每一个位的要求进行初步剪枝找出所有的八位子串&#xff0c;但是还是会存在19月的情况&#xff0c;为此还需要在CHECK函数…...

JavaScript 中 call 和 apply 的用法与区别

文章目录 前言一、 call 方法1.1 基本用法1.2 传递多个参数 二、apply 方法2.1 基本用法2.2 传递数组参数 三、call 和 apply 的区别四、实际应用场景4.1 借用方法4.2 继承与构造函数 五、总结 前言 在 JavaScript 中&#xff0c;call 和 apply 是两个非常重要的函数方法&…...

go程序调用k8s pod副本的名称IP手动赋值给configmap的参数

1、创建configmap --- apiVersion: v1 data:config.yaml: >-# config.yamlEtcd:Endpoints:- "etcd-server:2379"Username: ""Password: ""Exchanges:#- Name: "Binance"# Symbol: "BTCUSDT"# WSUrl: "wss://fstr…...

面试系列|蚂蚁金服技术面【1】

哈喽&#xff0c;大家好&#xff01;今天分享一下蚂蚁金服的 Java 后端开发岗位真实社招面经&#xff0c;复盘面试过程中踩过的坑&#xff0c;整理面试过程中提到的知识点&#xff0c;希望能给正在准备面试的你一些参考和启发&#xff0c;希望对你有帮助&#xff0c;愿你能够获…...

使用傅里叶变换测量声卡的频率失真

文章目录 一、说明二、关于声卡的技术详述三、实验代码获取四、结论 一、说明 假如我希望使用我的声卡来模拟软件无线电&#xff0c;利用声音而不是射频信号。我的声卡能胜任这项任务吗&#xff1f;本文将研究一种技术来找出答案。另外&#xff0c;需要了解音频技术的读者也可…...

Selenium 自动化测试学习总结

大概了解一下即可&#xff0c;现在主要用的自动化工具是 playWright&#xff0c;它可以录制操作。 selenium是老款自动化测试工具&#xff0c;仍有很多可取之处。 安装&#xff1a; pip install selenium即可。然后下载浏览器的驱动包&#xff0c;注意不是浏览器&#xff01;…...

【HTML5】01-HTML摆放内容

本文介绍HTML5摆放标签的知识点。 目录 1. HTML概念 2. HTML骨架 3. 标签的关系 4. 标题标签 5. 段落标签 6. 换行和水平线 7. 文本格式化标签 8. 图像标签 图像 - 属性 9. 路径 相对路径 绝对路径 10. 超链接标签 11. 音频标签 12. 视频标签 1. HTML概念 HTM…...

内存管理:

我们今天来学习一下内存管理&#xff1a; 1. 内存分布&#xff1a; 我们先来看一下我们下面的图片&#xff1a; 这个就是我们的内存&#xff0c;我们的内存分为栈区&#xff0c;堆区&#xff0c;静态区&#xff0c;常量区&#xff1b; 我们的函数栈帧开辟消耗的内存就是我们…...

设计模式使用Java案例

代码设计要有可维护性&#xff0c;可复用性&#xff0c;可扩展性&#xff0c;灵活性&#xff0c;所有要使用设计模式进行灵活设计代码 创建型 简单工厂模式&#xff08;Simple Factory&#xff09; 简单工厂模式&#xff08;Simple Factory Pattern&#xff09;是一种创建型…...

Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实战指南

Spring Boot拦截器&#xff08;Interceptor&#xff09;与过滤器&#xff08;Filter&#xff09;深度解析&#xff1a;区别、实现与实战指南 一、核心概念对比 1. 本质区别 维度过滤器&#xff08;Filter&#xff09;拦截器&#xff08;Interceptor&#xff09;规范层级Serv…...

模运算的艺术:从基础到高阶的算法竞赛应用

在算法竞赛中&#xff0c;模运算&#xff08;取模运算&#xff09;是一个非常重要的概念&#xff0c;尤其在处理大数、防止溢出、以及解决与周期性相关的问题时。C 中的模运算使用 % 运算符&#xff0c;但它的行为和使用场景需要特别注意。 1. 模运算的基本概念 模运算是指求一…...

Java 并发编程——Java BIO NIO Socket编程

参考Java 并发编程——Java BIO NIO Socket编程 BIO&#xff1a;阻塞式编程模型 Socket 服务端编程Socket 客户端编程 NIO&#xff1a;非阻塞式编程模型 NIO 介绍Java 中 NIO 非阻塞式与前面 BIO 阻塞式的区别Java NIO类库包含以下三个核心组件ServerSocketChannel 服务端编程…...

ST电机库电流采样 三电阻单ADC

一、概述 下图是三电阻采样的电路结构 其中流过三相系统的电流I1、I2、I3遵循以下关系: 因此,为了重建流过普通三相负载的电流,在我们可以用以上公式计算的情况下,只需要对三相中的两相进行采样即可。 STM32的ADC可以很灵活的配置成同步采集两路ADC数据,…...

【网络】什么是 IHL(Internet Header Length,首部长度)TTL(Time To Live,生存时间)?

在 IPv4 数据报文中&#xff0c;IHL&#xff08;Internet Header Length&#xff0c;首部长度&#xff09;、TTL&#xff08;Time To Live&#xff0c;生存时间&#xff09; 和 TIL 涉及到 IP 数据包的结构和生命周期。以下是对它们的详细解释&#xff1a; &#x1f4cc; 1. IH…...

现代密码学 | 具有保密和认证功能的安全方案

1.案例背景 1.1 2023年6月&#xff0c;微软云电子邮件泄露 事件描述&#xff1a; 2023年6月&#xff0c;属于多家美国政府机构的微软云电子邮件账户遭到非法入侵&#xff0c;其中包括了多位高级政府官员的电子邮件。据报道&#xff0c;美国国务院的10个邮件账户中共有6万封电…...

一款基于Python的从常规文档里提取图片的简单工具开发方案

一款基于Python的从常规文档里提取图片的简单工具开发方案 1. 环境准备 安装必需库 pip install python-docx PyMuPDF openpyxl beautifulsoup4 pillow pip install pdfplumber # PDF解析备用方案 pip install tk # Python自带&#xff0c;无需安装工具选择 开发环…...

JetBrains(全家桶: IDEA、WebStorm、GoLand、PyCharm) 2024.3+ 2025 版免费体验方案

JetBrains&#xff08;全家桶: IDEA、WebStorm、GoLand、PyCharm&#xff09; 2024.3 2025 版免费体验方案 前言 JetBrains IDE 是许多开发者的主力工具&#xff0c;但从 2024.02 版本起&#xff0c;JetBrains 调整了试用政策&#xff0c;新用户不再享有默认的 30 天免费试用…...

Pytorch实现之BCGAN实现双生成器架构的人脸面部生成

简介 简介:通过双生成器架构与重建损失进行循环的生成训练,实现人脸面部表情合成。 论文题目:BCGAN: Facial Expression Synthesis by Bottleneck-Layered Conditional Generative Adversarial Networks (基于瓶颈分层条件生成对抗网络的面部表情合成) 会议:2021 15th…...

智慧加油站小程序数据库设计文档

智慧加油站系统 - 数据库与API设计文档 1. 数据库设计 1.1 ER模型 系统的核心实体关系如下&#xff1a; 用户(User) ---< 订单(Order) ---< 加油记录(RefuelRecord)| | || | vv v …...

Docker生存手册:安装到服务一本通

文章目录 一. Docker 容器介绍1.1 什么是Docker容器&#xff1f;1.2 为什么需要Docker容器&#xff1f;1.3 Docker架构1.4 Docker 相关概念1.5 Docker特点 二. Docker 安装2.1 查看Linux内核版本2.2 卸载老版本docker&#xff0c;避免产生影响2.3 升级yum 和配置源2.4 安装Dock…...

Linux内核传输层UDP源码分析

一、用户数据包协议&#xff08;UDP&#xff09; 1.UDP数据报头 UDP 提供面向消息的不可靠传输&#xff0c;但没有拥塞控制功能。很多协议都使用 UDP&#xff0c;如用于 IP 网络传输音频和视频的实时传输协议 (Real-time Transport Protocol&#xff0c;RTP)&#xff0c;此类型…...

FPGA学习(二)——实现LED流水灯

FPGA学习(二)——实现LED流水灯 目录 FPGA学习(二)——实现LED流水灯一、DE2-115时钟源二、控制6个LED灯实现流水灯1、核心逻辑2、代码实现3、引脚配置4、实现效果 三、模块化代码1、分频模块2、复位暂停模块3、顶层模块 四、总结 一、DE2-115时钟源 DE2-115板子包含一个50MHz…...

E1-最远距离(stl使用)

题目描述 给定一个数组&#xff0c;请你找出数组中相同元素之间的最远距离。若数组中不存在相同元素&#xff0c;则输出 null。 输入描述 输入一个数组&#xff0c;数组长度不超过 10000。格式请见用例。 输出描述 输出数组中相同元素的最远距离。 用例 输入 [3, 2, 3,…...

Linux如何在设备树中表示和引用设备信息

DTS基本知识 dts 硬件的相应信息都会写在.dts为后缀的文件中&#xff0c;每一款硬件可以单独写一份xxxx.dts&#xff0c;一般在Linux源码中存在大量的dts文件&#xff0c;对于arm架构可以在arch/arm/boot/dts找到相应的dts&#xff0c;一个dts文件对应一个ARM的machie。 dtsi 值…...