常见限流算法及实现

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();}}}
}


对比总结

方式

适用场景

固定窗口

简单低频场景

滑动窗口

需平滑限流的场景

漏桶算法

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

令牌桶算法

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

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

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

相关文章

《TCP/IP网络编程》学习笔记 | Chapter 18:多线程服务器端的实现

《TCP/IP网络编程》学习笔记 | Chapter 18&#xff1a;多线程服务器端的实现 《TCP/IP网络编程》学习笔记 | Chapter 18&#xff1a;多线程服务器端的实现线程的概念引入线程的背景线程与进程的区别 线程创建与运行pthread_createpthread_join可在临界区内调用的函数工作&#…

创新实践分享:基于边缘智能+扣子的智能取物机器人解决方案

在 2024 年全国大学生物联网设计竞赛中&#xff0c;火山引擎作为支持企业&#xff0c;不仅参与了赛道的命题设计&#xff0c;还为参赛队伍提供了相关的硬件和软件支持。以边缘智能和扣子的联合应用为核心&#xff0c;参赛者们在这场竞赛中展现出了卓越的创新性和实用性&#xf…

QT:动态属性和对象树

动态对象 1.添加Q_PROPERTY对象 #ifndef MYPROPERTYCLASS_H #define MYPROPERTYCLASS_H#include <QObject>class MyPropertyClass : public QObject {Q_OBJECTQ_PROPERTY(QString mask READ mask WRITE setMask NOTIFY maskChanged) public:explicit MyPropertyClass(Q…

MobileNet家族:从v1到v4的架构演进与发展历程

MobileNet 是一个专为移动设备和嵌入式系统设计的轻量化卷积神经网络&#xff08;CNN&#xff09;家族&#xff0c;旨在在资源受限的环境中实现高效的图像分类、对象检测和语义分割等任务。自 2017 年首次推出以来&#xff0c;MobileNet 经历了从 v1 到 v4 的多次迭代&#xff…

在 Windows 上使用 choco 安装 mkcert 并配置 Vue 运行HTTPS

解决在Windows上使用Vue本地运行HTTPS的问题,vue-cli或vite都可以使用 步骤 1&#xff1a;确认 Chocolatey 是否已安装 1. 检查 choco 命令是否可用 打开 PowerShell&#xff08;管理员权限&#xff09;&#xff0c;输入&#xff1a; choco -v如果显示版本号&#xff08;如…

【PHP】新版本特性记录(持续更新)

文章目录 前言PHP 7.01&#xff09;NULL合并运算符&#xff1a;??2&#xff09;参数、返回值支持类型声明3&#xff09;太空船操作符&#xff1a;<>4&#xff09;通过 define 定义常量数组5&#xff09;匿名类实例化6&#xff09;字符串里使用\u转义unicode codepoint …

【记】如何理解kotlin中的委托属性?

1. 什么是委托属性&#xff1f; 委托属性的核心思想是&#xff1a; 你可以将一个属性的 getter 和 setter 的逻辑交给一个外部对象&#xff08;称为委托对象&#xff09;来处理。这个外部对象负责存储属性的值&#xff0c;并提供自定义的 get 和 set 行为。 通过委托属性&am…

使用自动导入后,eslint报错 eslint9

前提&#xff1a;使用pnpm create vuelatest创建vue应用&#xff0c;并且在创建项目时就勾选eslint和prettier&#xff0c;不然有些配置还需要手动配&#xff0c;比如解决eslint和prettier的冲突问题 1. 解决使用自动导入后Eslint报错问题 配置vite.config.ts // 自动导入api…

springboot EasyExcel 实现导入导出

1. 添加依赖 确保 Maven 依赖中包含 EasyExcel 3.0.5&#xff1a; <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.0.5</version></dependency><!-- excel工具 --><dep…

实现悬浮按钮拖动,兼容h5和微信小程序

h5用js写&#xff0c;微信小程序用 代码里面没有完全实现吸附边缘的功能&#xff0c;需要吸附边缘的话还得自己再完善下&#xff08;h5的吸附边缘是可以的&#xff0c;小程序的还有点问题&#xff09; 主要功能是&#xff1a;图片上写文字的悬浮按钮&#xff0c;文字使用的是…

2、操作系统之软件基础

一、硬件支持系统 &#xff0c;系统管理硬件 操作系统核心功能可以分为&#xff1a; 守护者&#xff1a;对硬件和软件资源的管理协调者&#xff1a;通过机制&#xff0c;将各种各样的硬件资源适配给软件使用。 所以为了更好的管理硬件&#xff0c;操作系统引进了软件。其中3大…

17 | 实现简洁架构的 Biz 层

提示&#xff1a; 所有体系课见专栏&#xff1a;Go 项目开发极速入门实战课&#xff1b;欢迎加入 云原生 AI 实战 星球&#xff0c;12 高质量体系课、20 高质量实战项目助你在 AI 时代建立技术竞争力&#xff08;聚焦于 Go、云原生、AI Infra&#xff09;&#xff1b;本节课最终…

idea更新git代码报错No Git Roots

idea更新git代码报错&#xff1a; No Git Roots None of configured Git roots are under Git. The configured directory must have ".git directory in it.但是本地项目里是存在.git文件的&#xff0c;就是突然间不能更新代码了 然后尝试重新拉新项目代码提示: Git i…

Webpack 知识点整理

​ 1. 对 webpack 的理解&#xff1f;解决了什么问题&#xff1f; Webpack 是前端工程化领域的核心工具&#xff0c;其核心定位是模块打包器&#xff08;Module Bundler&#xff09;&#xff0c;通过将各类资源&#xff08;JS、CSS、图片等&#xff09;视为模块并进行智能整合…

[Hello-CTF]RCE-Labs超详细WP-Level13Level14(PHP下的0/1构造RCE命令简单的字数限制RCE)

Level 13 源码分析 这题又回到了 PHP重点关注preg_match("/[A-Za-z0-9\"%*,-.\/:;>?[\]^|]/", $cmd)禁用了所有数字, 并且回到了 PHP, 没办法用上一关的方法进行绕过但是比起上一关, 给我们少绕过了 &, ~, _似乎有其他方法 解题分析 利用 $(()) 和 …

Qt 控件概述 QWdiget 1.1

目录 qrc机制 qrc使用 1.在项目中创建一个 qrc 文件 2.将图片导入到qrc文件中 windowOpacity&#xff1a; cursor 光标 cursor类型 自定义Cursor font tooltip focusPolicy styleSheet qrc机制 之前提到使用相对路径的方法来存放资源&#xff0c;还有一种更好的方式…

【eNSP实战】将路由器配置为DHCP服务器

拓图 要求&#xff1a; 为 office100 和 office200 分别配置地址池 AR1接口配置 interface GigabitEthernet0/0/0ip address 192.168.100.1 255.255.255.0 # interface GigabitEthernet0/0/1ip address 192.168.200.1 255.255.255.0 AR1路由器上创建office100地址池 [AR1…

数据结构——顺序表seqlist

前言&#xff1a;大家好&#x1f60d;&#xff0c;本文主要介绍了数据结构——顺序表部分的内容 目录 一、线性表的定义 二、线性表的基本操作 三.顺序表 1.定义 2. 存储结构 3. 特点 四 顺序表操作 4.1初始化 4.2 插入 4.2.1头插 4.2.2 尾插 4.2.3 按位置插 4.3 …

OSPF | LSDB 链路状态数据库 / SPF 算法 / 实验

注&#xff1a;本文为 “OSPF | LSDB / SPF ” 相关文章合辑。 LSDB 和 SPF 算法 潇湘浪子的蹋马骨汤 发布 2019-02-15 23:58:46 1. 链路状态数据库 (LSDB) 链路状态协议除了执行洪泛扩散链路状态通告&#xff08;LSA&#xff09;以及发现邻居等任务外&#xff0c;其第三个任…

前端---CSS(前端三剑客)

1.基本语法规范 选择器 {⼀条/N条声明} • 选择器决定针对谁修改 (找谁) • 声明决定修改啥. (⼲啥) • 声明的属性是键值对. 使⽤ ; 区分键值对, 使⽤ : 区分键和值 比如&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta…