常见限流算法及实现

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.rhkb.cn/news/35030.html

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

相关文章

【linux】虚拟机执行sudo yum isntall perl报错 could not retrieve mirrorlist htt:

项目场景&#xff1a; 提示&#xff1a;虚拟机安装拓展包&#xff0c;sudo yum install perl Virtualbox 在不安装增强功能扩展的情况下, 无法自适应分辨率和共享剪切板等操作 问题描述 原因分析&#xff1a; 提示&#xff1a;这里填写问题的分析&#xff1a; 出现这个错误是因…

网络编程知识预备阶段

1. OSI七层模型 OSI&#xff08;Open System Interconnect&#xff09;七层模型是一种将计算机网络通信协议划分为七个不同层次的标准化框架。每一层都负责不同的功能&#xff0c;从物理连接到应用程序的处理。这种模型有助于不同的系统之间进行通信时&#xff0c;更好地理解和…

我的Gitee

算法与数据结构: 浙海大小趴菜的一些记录 后续也会更新一些项目&#xff0c;小趴菜以后也会变得很厉害

Collection合集(单列集合)

Collection代表单列集合&#xff0c;每个元素&#xff08;数据&#xff09;只包含一个值。Collection实际上是一个泛型接口 Collection集合常用API&#xff1a; 代码实现&#xff1a; Collection集合遍历 遍历方式一&#xff1a;迭代器 迭代器是用来遍历集合的专用方式&#…

旅游类小程序界面设计

产品概述 艾啦游是一款互联网旅游类小程序&#xff0c;致力于国内精品旅游&#xff0c;以及拥有自由行、专属热榜单、出行攻略等诸多功能&#xff0c;汇聚了许多国内的人气景点&#xff0c;与诸多城市的酒店也保持合作&#xff0c;打造一体式旅行服务&#xff0c;更有不断上新…

移动端开发基础与常见布局

一、移动端基础 1.浏览器现状 ⑴.PC端常见浏览器 360浏览器、谷歌浏览器、火狐浏览器、QQ浏览 器、百度浏览器、搜狗浏览器、IE浏览器。 ⑵.移动端常见浏览器 UC浏览器&#xff0c;QQ浏览器&#xff0c;欧朋浏览器&#xff0c; 百度手机浏览器&#xff0c;360安全浏览器&am…

[算法] 贪心--矩阵消除游戏

文章目录 1. 题意2. 思路贪心思路1思路1并不正确思路1为什么是错误的?这道题该如何求解?枚举思路是超时的!枚举 贪心 3. 编码 今天咱们来分享一道基础的贪心题目 -> 矩阵消除游戏 对于贪心算法的题目, 我感觉是对于初学者没必要太注重证明过程, 因为这玩意的变数比较大, …

数学——A. K-divisible Sum + D. Exam in MAC

A. K-divisible Sum 题目&#xff1a; 思路&#xff1a; 以下 “[xxx]” 符号均代表向上取整 我们假设总和是sum&#xff0c;那么就有sum k * cnt 要想最大值最小&#xff0c;肯定是要让sum尽可能小&#xff0c;这样每个元素都能变小 最小情况是 sum 恰好等于 n 时&#…

Docker 》》Docker Compose 》》network 网络 compose

docker 默认的网络 三种模式 # 列出所有当前主机上或Swarm集群上的网络 docker network ls#查看网络详情 docker network inspect network名称# 清除未使用的docker网络 docker network prune -f# 创建网络 ocker network create -d bridge 网络名称 docker network create –s…

RabbitMQ延迟消息

文章目录 延迟消息死信交换机延迟消息延迟消息应用场景 延迟消息 生产者在发送消息的时候指定一个时间&#xff0c;消费者不会立即收到该消息&#xff0c;而是在指定时间之后才收到消息&#xff0c;这就是延迟消息。 比如说这么一个场景&#xff0c;用户下单后将商品库存进行…

phpstudy+phpstorm+xdebug【学习笔记】

配置PHPStudy 配置PHPSTORM phpstorm选择PHP版本 配置DEBUG 设置服务器 编辑配置 学习参考链接&#xff1a;&#xff1a;https://blog.csdn.net/m0_60571842/article/details/133246064

58.Harmonyos NEXT 图片预览组件架构设计与实现原理

温馨提示&#xff1a;本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦&#xff01; Harmonyos NEXT 图片预览组件架构设计与实现原理 文章目录 Harmonyos NEXT 图片预览组件架构设计与实现原理效果预览一、组件架构概述1. 核心组件层…

Android 手机启动过程

梳理 为了梳理思路&#xff0c;笔者画了一幅关于 Android 手机启动的过程图片内容纯属个人见解&#xff0c;如有错误&#xff0c;欢迎各位指正

Chat-TTS-UI:文字转语音 - 本地部署方案

Chat-TTS-UI 是一个基于 ChatTTS 模型的本地网页界面,专为满足用户在信息过载时代轻松获取大量文字信息的需求而设计。它支持中英文混合输入、多种音色选择,并提供 API 接口,方便开发者集成到其他应用中。其简洁易用的网页界面、细粒度控制以及 GPU 加速等高级功能,使其广泛…

11. Pandas :操作Excel文件(Excel报表的案例研究)

从一个装有各种 Excel 文件的文件夹开始&#xff0c;这些文件需要被整合到 Excel 报表中。 它们包含了虚构的电信运营商在全美各营业厅的套餐&#xff08;金、银、铜&#xff09;销售情况。每个月有两个文件&#xff0c;子文件夹 new 中的是新用户&#xff0c;子文件夹 existin…

一周学会Flask3 Python Web开发-SQLAlchemy添加数据操作-班级模块

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili SQLAlchemy提供session.add()方法添加model实体数据&#xff0c;以及提供session.commit()提交事务。 首先list.html加一个添…

大型语言模型与强化学习的融合:迈向通用人工智能的新范式——基于基础复现的实验平台构建

1. 引言 大型语言模型&#xff08;LLM&#xff09;在自然语言处理领域的突破&#xff0c;展现了强大的知识存储、推理和生成能力&#xff0c;为人工智能带来了新的可能性。强化学习&#xff08;RL&#xff09;作为一种通过与环境交互学习最优策略的方法&#xff0c;在智能体训…

Axure大屏可视化原型模板及素材:数据可视化的高效解决方案

数据可视化已成为企业决策、运营分析、市场洞察的重要工具。数据可视化大屏&#xff0c;作为数据展示和交互的直观平台&#xff0c;能够实时呈现关键数据&#xff0c;帮助企业快速做出决策。Axure作为原型设计领域的领先工具&#xff0c;以其丰富的组件库、强大的交互设计能力和…

图片填充容器,如何描述

【图片需要完全填充/拉伸以适应容器尺寸&#xff0c;不保持原始比例&#xff0c;使用 object-fit: fill 属性实现】 效果&#xff1a; 代码案例&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8">&l…

缓存和客户端数据存储体系(Ark Data Kit)--- 应用数据持久化(首选项持久化、K-V、关系型数据库)持续更新中...

Core File Kit做怎删改查操作不便&#xff0c;用Ark Data Kit。 功能介绍 ArkData &#xff08;方舟数据管理&#xff09;为开发者提供数据存储、数据管理和数据同步能力&#xff0c;比如联系人应用数据可以保存到数据库中&#xff0c;提供数据库的安全、可靠以及共享访问等管…