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

接口限频算法:漏桶算法、令牌桶算法、滑动窗口算法

文章目录

  • 限频三大算法对比与选型建议
  • 一、漏桶算法(Leaky Bucket Algorithm)
    • 1.核心原理
    • 2.实现
    • 3.为什么要限制漏桶容量
    • 4.优缺点分析
  • 二、令牌桶算法(Token Bucket Algorithm)
    • 1.核心原理
    • 2.实现
      • (1)单机实现
      • (2)分布式实现
    • 3.优缺点分析
  • 三、滑动窗口算法(Sliding Window Algorithm)
    • 1.核心原理
    • 2.实现
    • 3.优缺点分析

限频三大算法对比与选型建议

维度漏桶算法令牌桶算法滑动窗口算法
流量平滑性强(固定速率)中(允许突发)弱(依赖窗口粒度)
实现复杂度简单中等(需处理令牌生成)中等(需处理窗口滑动)

一、漏桶算法(Leaky Bucket Algorithm)

1.核心原理

漏桶算法的核心是恒定速率输出,无论输入流量如何波动,输出始终保持稳定。其工作机制可类比为一个底部有固定孔径的水桶:

  • 输入:请求以任意速率流入桶中(如突发流量)。
  • 输出:桶以固定速率(如100请求/秒)处理请求,超出桶容量的请求直接丢弃。

2.实现

  • 实现:使用队列存储请求,通过定时任务以固定速率从队列中取出请求处理。若队列满则拒绝新请求。

在非单节点场景下,可使用消息队列中间件,或者Redis模拟队列,来实现这个算法。

3.为什么要限制漏桶容量

有容量限制 vs 无容量限制:对比分析

场景有容量限制(标准漏桶)无容量限制(无限漏桶)
流量平滑效果✅ 稳定输出,突发请求被缓存或丢弃✅ 稳定输出(但突发请求全部缓存)
内存/缓冲区占用🟡 有限占用(取决于桶容量)❌ 可能无限占用,导致OOM(内存溢出)
突发流量处理🟡 超过容量的请求被丢弃,保护下游系统❌ 缓存所有请求,下游可能被持续高负载拖垮
适用场景真实系统(如API接口限频、网络流量控制)理论场景(无实际意义,无法用于生产环境)

4.优缺点分析

  • 优点
    • 绝对平滑:严格控制输出速率,适合对稳定性要求极高的场景(如金融交易接口)。
    • 实现简单:只需维护队列和固定速率处理器,无需复杂逻辑。
  • 缺点
    • 资源浪费:突发流量会被直接丢弃,无法利用系统空闲资源。
    • 灵活性差:无法区分请求优先级,所有超额请求同等处理。

二、令牌桶算法(Token Bucket Algorithm)

1.核心原理

令牌桶算法通过令牌生成与消耗实现限流,允许一定程度的突发流量:

  • 令牌生成:系统以固定速率(如100令牌/秒)向桶中添加令牌,桶容量上限为burst_size(如200令牌)。
  • 请求处理:每个请求需消耗一个令牌,无令牌则拒绝。若桶满,新生成的令牌会被丢弃。

2.实现

(1)单机实现

Guava的RateLimiter采用令牌桶算法,支持动态调整速率和突发容量。

RateLimiter rateLimiter = RateLimiter.create(100.0); // 每秒生成100令牌
if (rateLimiter.tryAcquire()) { // 尝试获取令牌// 处理请求
} else {// 限流
}

(2)分布式实现

在分布式系统中,可以利用 Redis 的原子操作和 Lua 脚本来实现一个线程安全的令牌桶。

  • 使用 Redis 实现令牌桶的关键在于:
    • 使用原子操作保证令牌增减的线程安全
    • 实现令牌的自动生成逻辑
    • 高效地判断是否允许请求通过
原子操作
允许
拒绝
获取令牌数与时间戳
执行Lua脚本
计算时间差
计算新生成令牌数
计算当前可用令牌数
判断是否足够?
消耗令牌
拒绝请求
更新Redis状态
返回处理结果
客户端请求
获取当前时间戳
拼接Redis键
是否允许?
执行业务逻辑
返回限流响应

3.优缺点分析

  • 优点
    • 支持突发流量:允许短时间内消耗桶内累积的令牌,提升资源利用率(如电商秒杀)。
    • 参数灵活:可通过调整rate(平均速率)和burst_size(突发容量)平衡平滑性与突发性。
  • 缺点
    • 实现复杂度较高:需维护令牌生成、存储和消耗逻辑。
    • 流量尖刺风险:突发流量可能瞬间耗尽令牌,导致后续请求被拒绝。

三、滑动窗口算法(Sliding Window Algorithm)

1.核心原理

滑动窗口算法通过时间窗口划分与计数实现限流,精度随窗口细分而提升:

  • 窗口划分:将时间轴划分为多个固定长度的子窗口(如1秒划分为10个0.1秒的子窗口)。
  • 计数与滑动:统计当前窗口内的请求数,当窗口滑动时,旧子窗口的计数逐渐过期。

2.实现

在分布式系统中,可以利用 Redis 的原子操作和 Lua 脚本来实现一个这个算法。

Redis Lua脚本逻辑
获取窗口内所有时间戳
通过Lua脚本操作Redis
移除过期时间戳< current_time - T
添加当前时间戳到窗口
统计窗口内时间戳数量
判断数量是否超过阈值N
客户端请求
获取当前时间戳
生成窗口键key
拒绝请求
允许请求

3.优缺点分析

  • 优点
    • 时间敏感性强:可精确控制时间维度的请求频率(如“每分钟最多100次”)。
    • 动态调整窗口:支持秒级、分钟级等不同粒度的限流规则。
  • 缺点
    • 临界问题:窗口切换时可能出现双倍请求(如0.9秒和1.1秒各发100次)。
    • 分布式同步成本:需依赖Redis等分布式缓存,引入额外延迟。
http://www.xdnf.cn/news/12330.html

相关文章:

  • 小黑一层层削苹果皮式大模型应用探索:langchain中智能体思考和执行工具的demo
  • 深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
  • 鸿蒙开发——如何修改模拟器的显示图标/标题
  • 车牌识别技术解决方案
  • day46打卡
  • 如何防止服务器被用于僵尸网络(Botnet)攻击 ?
  • 进一步探究synchronized
  • 408第一季 - 数据结构 - 线性表II
  • Redis哨兵模式
  • 获1.3亿美元融资,NewLimit利用机器学习指导表观遗传程序设计,延长人类健康寿命研究已有初级成果
  • 自建 dnslog 回显平台:渗透测试场景下的隐蔽回显利器
  • Webpack的基本使用 - babel
  • leetcode78. 子集
  • vue项目引入tailwindcss
  • 实战设计模式之模板方法模式
  • SpringBoot 自动化部署实战:CI/CD 整合方案与避坑指南
  • 数据库正常,但后端收不到数据原因及解决
  • 基于sqlite的任务锁(支持多进程/多线程)
  • RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
  • BugKu Web渗透之需要管理员
  • vue+elementui 网站首页顶部菜单上下布局
  • Linux共享内存原理及系统调用分析
  • N8N概述
  • vscode vue debug
  • solidity中sar和>>的区别
  • C++.OpenGL (1/64) 创建窗口(Hello Window)
  • 解决cocos 2dx/creator2.4在ios18下openURL无法调用的问题
  • 408第一季 - 数据结构 - 线性表
  • React源码阅读-fiber核心构建原理
  • 解决获取视频第一帧黑屏问题