Java:限流器(RateLimiter)原理与实现

限流器(RateLimiter)主要有两种算法:

  • 漏桶算法
  • 令牌桶算法

它们都是网络世界中流量整形(Traffic Shaping)或速率限制(Rate Limiting)时经常使用的算法。

漏桶算法

漏桶算法(Leaky Bucket),它的主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。漏桶算法提供了一种机制,通过它,突发流量可以被整形以便为网络提供一个稳定的流量。

漏桶可以看作是一个带有常量服务时间的单服务器队列,如果漏桶(包缓存)溢出,那么数据包会被丢弃。 在网络中,漏桶算法可以控制端口的流量输出速率,平滑网络上的突发流量,实现流量整形,从而为网络提供一个稳定的流量。

如图所示,把请求比作是水,水来了都先放进桶里,并以限定的速度出水,当水来得过猛而出水不够快时就会导致水直接溢出,即拒绝服务。

令牌桶算法

令牌桶算法(Token Bucket),用来控制发送到网络上的数据的数目,并允许突发数据的发送。

令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。从原理上看,令牌桶算法和漏桶算法是相反的,一个“进水”,一个是“漏水”。

漏桶算法&令牌桶算法的区别

漏桶算法与令牌桶算法的区别在于,漏桶算法能够强行限制数据的传输速率,令牌桶算法能够在限制数据的平均传输速率的同时还允许某种程度的突发传输。

需要注意的是,在某些情况下,漏桶算法不能够有效地使用网络资源,因为漏桶的漏出速率是固定的,所以即使网络中没有发生拥塞,漏桶算法也不能使某一个单独的数据流达到端口速率。因此,漏桶算法对于存在突发特性的流量来说缺乏效率。而令牌桶算法则能够满足这些具有突发特性的流量。通常,漏桶算法与令牌桶算法结合起来为网络流量提供更高效的控制。

下面介绍Java中一些实现了令牌桶算法的常用组件。

单机限流

1、resilience4j-ratelimiter

https://resilience4j.readme.io/docs/ratelimiter

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-ratelimiter</artifactId>
    <version>1.3.1</version>
</dependency>

RateLimiterConfig config = RateLimiterConfig.custom()
  .limitRefreshPeriod(Duration.ofMillis(1))
  .limitForPeriod(10)
  .timeoutDuration(Duration.ofMillis(25))
  .build();

// Create registry
RateLimiterRegistry rateLimiterRegistry = RateLimiterRegistry.of(config);

// Use registry
RateLimiter rateLimiterWithDefaultConfig = rateLimiterRegistry
  .rateLimiter("name1");

RateLimiter rateLimiterWithCustomConfig = rateLimiterRegistry
  .rateLimiter("name2", config)

2、Guava: Google Core Libraries for Java

https://github.com/google/guava

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>28.2-jre</version>
  <!-- or, for Android: -->
  <version>28.2-android</version>
</dependency>

RateLimiter limiter = RateLimiter.create(1);//限制qps最大为1
System.out.println(limiter.acquire()); //输出阻塞的时间

 

分布式限流

1、Redisson - Redis Java client

https://github.com/redisson/redisson

<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.12.1</version>
</dependency>

Config config = Config.fromYAML(new File("config-file.yaml"));
RedissonClient redisson = Redisson.create(config);
RRateLimiter rateLimiter = redisson.getRateLimiter("myRateLimiter");

 2、alibaba - Sentinel

https://github.com/alibaba/Sentinel

https://github.com/alibaba/Sentinel/wiki/介绍

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.8.1</version>
</dependency>

private static void initFlowRules(){
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule = new FlowRule();
    rule.setResource("HelloWorld");
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    // Set limit QPS to 20.
    rule.setCount(20);
    rules.add(rule);
    FlowRuleManager.loadRules(rules);
}
public static void main(String[] args) {
    // 配置规则.
    initFlowRules();

    while (true) {
        // 1.5.0 版本开始可以直接利用 try-with-resources 特性
        try (Entry entry = SphU.entry("HelloWorld")) {
            // 被保护的逻辑
            System.out.println("hello world");
	} catch (BlockException ex) {
            // 处理被流控的逻辑
	    System.out.println("blocked!");
	}
    }
}

参考文档

接口限流算法:漏桶算法和令牌桶算法
https://my.oschina.net/u/4129361/blog/3053350

漏桶算法&令牌桶算法理解及常用的算法
https://www.jianshu.com/p/c02899c30bbd

 

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java实现API调用限流可以通过以下步骤: 1. 定义限流策略 首先,需要定义限流策略。常见的限流策略包括:固定窗口计数、滑动窗口计数、令牌桶、漏桶等。可以根据实际需求选择合适的限流策略。例如,可以定义一个固定窗口计数,每秒只允许调用API 100次。 2. 实现限流 其次,需要根据限流策略实现一个限流。可以使用Java中的并发工具包(如Semaphore、AtomicInteger等)来实现。例如,可以使用Semaphore来实现一个固定窗口计数限流。 3. 在API中使用限流 最后,在API中调用限流来限制API的调用次数。可以在API的入口处加上限流的逻辑。例如,可以在API的入口处调用限流的acquire()方法,来获取限流令牌。如果获取令牌成功,则调用API;否则,返回错误码。 以下是一个使用Semaphore实现固定窗口计数限流示例: ```java import java.util.concurrent.Semaphore; public class ApiRateLimiter { private final Semaphore semaphore; public ApiRateLimiter(int rateLimit) { this.semaphore = new Semaphore(rateLimit); } public void enter() throws InterruptedException { semaphore.acquire(); } public void leave() { semaphore.release(); } } ``` 在API中使用限流的示例: ```java public class Api { private static final ApiRateLimiter rateLimiter = new ApiRateLimiter(100); public void callApi() { try { rateLimiter.enter(); // 调用API } catch (InterruptedException e) { // 处理异常 } finally { rateLimiter.leave(); } } } ``` 总之,实现Java API调用限流需要定义限流策略、实现限流和在API中使用限流三个步骤。这个过程需要编写大量的代码,并且需要考虑线程安全和性能等方面的问题。但是,一旦实现成功,API调用限流可以有效地控制API的调用次数,防止API被滥用和攻击,从而提高系统的安全性和可用性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值