首页 > 其他分享 >guava的限流器实现

guava的限流器实现

时间:2024-10-17 14:48:39浏览次数:6  
标签:令牌 请求 permits 实现 long 获取 限流 guava

限流器

如有侵权,请联系,无心侵权~
如有错误,欢迎批评指正!

1、限流器的概述

限流器是一种控制请求流量的机制,通常用于计算机网络、API、数据库等场景,以保护系统免受过载或滥用。

1.1、限流的目的

  • 性能保护:避免过多请求同时到达系统,导致性能下降或崩溃。
  • 资源管理:合理分配系统资源,确保服务质量。
  • 安全防护:防止恶意攻击(如 DDoS 攻击)或滥用(如接口频繁调用)。
  • 用户体验:平滑地处理流量,提供更好的用户体验。

1.2、限流策略

  • 固定窗口计数法:
    • 设定一个固定的时间窗口,记录在这个窗口内的请求次数。一旦请求次数超过设定限额,后续请求会被拒绝或延迟。
    • 优点:实现简单,适用于流量相对均匀的场景。
    • 缺点:在窗口边界会出现突发流量的问题。
  • 滑动窗口计数法:
    • 通过滑动窗口动态计算请求次数,避免固定窗口的瞬时爆发问题。滑动窗口更精细,可以平滑请求流量。
    • 优点:避免固定窗口的突发问题,提供更平滑的流量控制。
    • 缺点:实现复杂度相对较高。
  • 漏桶算法(Leaky Bucket):
    • 形象地将请求视作水流,一定数量的水(请求)流入桶中并缓慢泄漏。请求的速率是恒定的,即使瞬时请求量很高,也会被平滑处理。也就是请求放入到桶中,然后恒速进行消费。
    • 优点:通过稳定输出速率,有效平滑请求流量。
    • 缺点:若请求流量持续高于桶的容量,重要请求可能会被丢弃。
  • 令牌桶算法(Token Bucket):
    • 每个请求需要消耗一个令牌,系统每秒生成一定数量的令牌。当请求到达时,如果有令牌可用,则允许请求,否则拒绝。令牌桶允许突发请求,但保持平均速率。即,令牌放入到桶中,请求去桶中获取令牌。感觉和漏桶算法是反过来的。
    • 优点:允许突发请求,同时限制了平均流量。
    • 缺点:需要管理令牌的生成与消耗,稍显复杂。

2、令牌桶的算法实现-guava

2.1、源码

令牌桶算法是按照固定的频率生成令牌。当然,直观上我们可以使用信号量JUC包下的Semaphore来实现【通过一个定时器每间隔一定的时间就增加一个令牌,每个请求获取一个令牌】。
guava却只是通过一个指针来实现,这样实现有很多好处,例如,实现简单、并且限流主要发生在在高并发的情况下,系统压力已经临近极限了,此时使用定时器这个实现就有问题了。问题就出在定时器上,在高并发场景下,当系统压力已经临近极限的时候,定时器的精度误差会非常大,同时定时器本身会创建调度线程,也会对系统的性能产生影响。
com.google.common.util.concurrent.RateLimiter:

public abstract class RateLimiter {
	@CanIgnoreReturnValue
  public double acquire(int permits) {
    // 获取permits个令牌需要等待的时间
    long microsToWait = reserve(permits);
    // 线程sleep这么久【microsToWait】并且不能打断
    stopwatch.sleepMicrosUninterruptibly(microsToWait);
    // 等待时间从微秒转换为秒
    return 1.0 * microsToWait / SECONDS.toMicros(1L);
  }
  
  final long reserve(int permits) {
    // 校验permits的合法性
    checkPermits(permits);
    // 加锁
    synchronized (mutex()) {
      return reserveAndGetWaitLength(permits, stopwatch.readMicros());
    }
  }
  
  final long reserveAndGetWaitLength(int permits, long nowMicros) {
    // 获取最早令牌桶中有可用令牌的时间点
    long momentAvailable = reserveEarliestAvailable(permits, nowMicros);
    // 需要等待的时间
    return max(momentAvailable - nowMicros, 0);
  }
}

abstract class SmoothRateLimiter extends RateLimiter {
  @Override
  final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {
    resync(nowMicros);
    // nextFreeTicketMicros含义:获取令牌桶下次产生令牌的时间,这里直接赋值给returnValue,返回。所以,返回的是下次令牌桶有第一个令牌的时间,
    // 但是不满足requiredPermits个数。
    long returnValue = nextFreeTicketMicros;
    double storedPermitsToSpend = min(requiredPermits, this.storedPermits);
    double freshPermits = requiredPermits - storedPermitsToSpend;
    // 如果令牌不够,需要等待的时间。这个等待时间,也只是影响下一个获取限流器令牌的请求,不会影响本次
    long waitMicros =
        storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)
            + (long) (freshPermits * stableIntervalMicros);
		// 下次限流获取令牌桶的时间点
    this.nextFreeTicketMicros = LongMath.saturatedAdd(nextFreeTicketMicros, waitMicros);
    this.storedPermits -= storedPermitsToSpend;
    return returnValue;
  }
  void resync(long nowMicros) {
    // if nextFreeTicket is in the past, resync to now
    if (nowMicros > nextFreeTicketMicros) {
      double newPermits = (nowMicros - nextFreeTicketMicros) / coolDownIntervalMicros();
      storedPermits = min(maxPermits, storedPermits + newPermits);
      nextFreeTicketMicros = nowMicros;
    }
  }
}

一句话:
你通过acquire(n)获取限流:

  • 这个限流器有令牌,会立刻让你通过,并且如果n比较大它会预支未来的令牌,未来一段时间所有的请求都被限流;

  • 这个令牌桶没有令牌,会等令牌桶有第一个令牌就会立刻返回。

2.2、测试验证

public class BaseTest {
  @Test
  public void testLimiter() {
    RateLimiter rateLimiter = RateLimiter.create(1);
    long time1 = System.currentTimeMillis();
    rateLimiter.acquire(10);
    long time2 = System.currentTimeMillis();
    System.out.println("第一次获取等待时间: " + (time2 - time1)/1000);
    rateLimiter.acquire(15);
    long time3 = System.currentTimeMillis();
    System.out.println("第二次获取等待时间: " + (time3 - time1)/1000);
    rateLimiter.acquire();
    long time4 = System.currentTimeMillis();
    System.out.println("第三次获取等待时间: " + (time4 - time1)/1000);
  }
}  

运行结果:

第一次获取等待时间: 0
第二次获取等待时间: 10
第三次获取等待时间: 25

很好验证了上面的说法。本次的获取的限流值只会影响下次的请求,会预支之后的令牌。
指导:
杜绝使用acquire(n),多个请求同时打过来,聚合到一起去限流器获取令牌,而应该是一个请求去令牌桶获取一次,调用acquire(1)

标签:令牌,请求,permits,实现,long,获取,限流,guava
From: https://blog.csdn.net/m0_50149847/article/details/143016962

相关文章

  • python+flask框架的代驾小程序设计与实现实现18(开题+程序+论文) 计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容选题背景随着城市化进程的加速和交通安全意识的提升,代驾服务逐渐成为人们日常生活中不可或缺的一部分。特别是在饮酒后或长途驾驶疲劳时,代驾服务为......
  • 剖析线程池实现原理
    前置推荐阅读:java并发之线程池使用-CSDN博客自定义实现一个带监控的线程池首先我们继承ThreadPoolExecutor,实现构造函数以及重写beforeExecute和afterExecute两个函数,具体调用我们会在代码实现层面进行详细的分析。importjava.util.concurrent.*;publicclassAsyncTh......
  • 使用 Dart 实现验证码识别与自动化登录
    安装所需依赖我们将使用以下依赖:http:用于发送HTTP请求,下载验证码图片。image:用于图像处理(如灰度化等操作)。TesseractOCR:通过系统调用Tesseract进行验证码识别。首先,确保在你的系统中安装了TesseractOCR,可以通过包管理器安装:bashsudoaptinstalltesseract-ocr然......
  • python+flask框架的传智健康医疗项目设计与实现(开题+程序+论文) 计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容选题背景随着信息技术的飞速发展,健康医疗行业正经历着前所未有的变革。关于健康医疗信息化的研究,现有研究主要以电子病历系统、远程医疗服务以及医......
  • python+flask框架的传智健康医疗项目设计与实现(开题+程序+论文) 计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容选题背景随着信息技术的飞速发展和人口老龄化的加剧,健康医疗行业正经历着前所未有的变革。当前,国内外关于健康医疗信息化的研究主要集中在医疗信息......
  • python+flask框架的城固一中学生信息管理系统的设计与实现(开题+程序+论文) 计算机毕
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容选题背景在当前信息化时代背景下,学校信息管理系统的建设已成为提升教育管理水平、优化资源配置、提高教学效率的重要手段。关于学生信息管理系统的......
  • 【计算机毕设选题推荐】基于Python的智能停车管理系统的设计与实现 【附源码+数据库+
    ✍✍计算机编程指导师⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java实战|SpringBoot/SSMPython实战项目|Django微信小程......
  • 【计算机毕设选题推荐】基于Python的学生选课系统的设计与实现 【附源码+数据库+部署
    ✍✍计算机编程指导师⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java实战|SpringBoot/SSMPython实战项目|Django微信小程......
  • 基于SSM的网上假发交易管理系统的设计与实现
    文未可获取一份本项目的java源码和数据库参考。伴随着Internet的蓬勃发展,电子商城作为电子商务的一种形式正以其高效、低成本的优势,逐步成为新兴的经营模式和理念。电子商城正适应了当今社会快节奏地生活,使顾客足不出户便可以方便快捷轻松地选购自己喜欢的商品。皮包作为一种......
  • jsp东哈驾校管理系统的设计与实现dy35m(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表学员,教练,报名登记,退学登记,练车预约,考试预约,报考信息,报考反馈,成绩信息开题报告内容一、项目背景随着汽车保有量的不断增加,驾驶培训行业迎来了巨大的发......