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

高可用之限流-04-fixed window 固定窗口

限流系列

开源组件 rate-limit: 限流

高可用之限流-01-入门介绍

高可用之限流-02-如何设计限流框架

高可用之限流-03-Semaphore 信号量做限流

高可用之限流-04-fixed window 固定窗口

高可用之限流-05-slide window 滑动窗口

高可用之限流-06-slide window 滑动窗口 sentinel 源码

高可用之限流-07-token bucket 令牌桶算法

高可用之限流 08-leaky bucket漏桶算法

高可用之限流 09-guava RateLimiter 入门使用简介 & 源码分析

固定窗口

计数器的方案比较简单。比如限制1秒钟内请求数最多为10个,每当进来一个请求,则计数器+1。

当计数器达到上限时,则触发限流。

时间每经过1秒,则重置计数器。

核心代码

重置计数器可以通过 loop 循环,也可以通过 CountDownLatch 达到类似的效果。

此处演示一下 CountDownLatch 的实现版本

public class LimitFixedWindow extends LimitAdaptor {/*** 日志* @since 0.0.4*/private static final Log LOG = LogFactory.getLog(LimitFixedWindow.class);/*** 上下文* @since 0.0.4*/private final ILimitContext context;/*** 计数器* @since 0.0.4*/private AtomicInteger counter = new AtomicInteger(0);/*** 限制状态的工具** 避免不同线程的 notify+wait 报错问题** @since 0.0.4*/private CountDownLatch latch = new CountDownLatch(1);/*** 构造器* @param context 上下文* @since 0.0.4*/public LimitFixedWindow(ILimitContext context) {this.context = context;// 定时将 count 清零。final long interval = context.interval();final TimeUnit timeUnit = context.timeUnit();// 任务调度ExecutorServiceUtil.singleSchedule(new Runnable() {@Overridepublic void run() {initCounter();}}, interval, timeUnit);}@Overridepublic synchronized void acquire() {// 超过阈值,则进行等待if (counter.get() >= this.context.count()) {try {LOG.debug("[Limit] fixed count need wait for notify.");latch.await();LOG.debug("[Limit] fixed count need wait end ");} catch (InterruptedException e) {Thread.currentThread().interrupt();LOG.error("[Limit] fixed count is interrupt", e);}}// 结束int value = this.counter.incrementAndGet();this.latch = new CountDownLatch(1);LOG.debug("[Limit] fixed count is " + value);}/*** 初始化计数器* @since 0.0.4*/private void initCounter() {LOG.debug("[Limit] fixed count init counter start");// 通知可以继续执行(这里不能无脑 notify)会卡主if(this.counter.get() >= this.context.count()) {this.counter = new AtomicInteger(0);LOG.debug("[Limit] fixed count notify all start");latch.countDown();LOG.debug("[Limit] fixed count notify all end");}  else {this.counter = new AtomicInteger(0);}}}

测试验证

public class LimitFixedWindowTest {private static final Log log = LogFactory.getLog(LimitFixedWindowTest.class);/*** 1S 内最多运行 1 次* @since 0.0.5*/private static final ILimit LIMIT = LimitBs.newInstance().interval(1).count(1).limit(LimitFixedWindow.class).build();static class LimitRunnable implements Runnable {@Overridepublic void run() {for(int i = 0; i < 3; i++) {LIMIT.acquire();log.info("{}-{}", Thread.currentThread().getName(), i);}}}public static void main(String[] args) {new Thread(new LimitRunnable()).start();new Thread(new LimitRunnable()).start();}}
  • 日志
13:57:54.845 [Thread-2] INFO  com.github.houbb.rate.limit.test.core.fixed.LimitFixedWindowTest - Thread-2-0
13:57:55.825 [Thread-3] INFO  com.github.houbb.rate.limit.test.core.fixed.LimitFixedWindowTest - Thread-3-0
13:57:56.826 [Thread-2] INFO  com.github.houbb.rate.limit.test.core.fixed.LimitFixedWindowTest - Thread-2-1
13:57:57.824 [Thread-3] INFO  com.github.houbb.rate.limit.test.core.fixed.LimitFixedWindowTest - Thread-3-1
13:57:58.826 [Thread-2] INFO  com.github.houbb.rate.limit.test.core.fixed.LimitFixedWindowTest - Thread-2-2
13:57:59.826 [Thread-3] INFO  com.github.houbb.rate.limit.test.core.fixed.LimitFixedWindowTest - Thread-3-2

存在的不足

这种简单的实现存在的一个问题,就是在两个周期的临界点的位置,可能会存在请求超过阈值的情况。比如有恶意攻击的人在一个周期即将结束的时刻,发起了等于阈值的请求(假设之前的请求数为0),并且在下一个周期开始的时刻也发起等于阈值个请求。

则相当于在这接近一秒的时间内系统受到了2倍阈值的冲击,有可能导致系统挂掉。

下一节将讲述滑动窗口,解决这个问题。

参考资料

限流技术总结

基于循环数组实现的带滑动窗口的计数器限流算法


http://www.mrgr.cn/news/48093.html

相关文章:

  • 【物联网技术与应用】 实验13:雨滴传感器实验
  • 学习记录2024/12/25;用C语言实现通讯录功能
  • DRÆM无监督异常检测(CVPR2021)
  • mysql的读写分离
  • Git的简介
  • HarmonyOs:创建线程的3种方式
  • MES系统中人机接口设计和开发研究
  • Pyke学习系列(pyke基础执行)(一)
  • Spring Boot 日志打印配置详解
  • 【C语言】自定义类型:联合体和枚举
  • C++编程:利用ARM硬件加速CRC32计算
  • vue基础语法的用法(API组合式风格)
  • maven
  • 小白萌新 JSAR 开发者工具之初体验——好用!
  • 《市场营销学》PPT课件.ppt
  • SAP S/4HANA 迁移:IT 高管实用指南
  • 探索未知,惊喜连连 —— 盲盒小程序开发文案
  • 【低代码】前端低代码开发日记2_遇到的问题(2)变量绑定
  • [单master节点k8s部署]34.ingress 反向代理(一)
  • 提升 Python 包下载速度的利器:cnpip
  • Datawhale 组队学习 文生图 Prompt攻防 task01
  • 解释Flask框架中的session和request对象
  • 模型预测控制工具包——ACADO:通过Cmake构建自己的优化问题
  • lnmp - RBAC方案设计与实现
  • 使用阿里云盘将服务器上的文件上传/下载到云盘/服务器
  • MySQL数据库详细学习要点