/rate-limiter

使用Guava提供的RateLimiter实现SpringBoot项目中基于注解的限流库.

Primary LanguageJava

rate-limiter

使用Guava提供的RateLimiter实现SpringBoot项目中基于注解的限流库.

Guava提供的RateLimiter可以限制物理或逻辑资源的被访问速率,咋一听有点像java并发包下的Samephore,但是又不相同,RateLimiter控制的是速率,Samephore控制的是并发量。

RateLimiter的原理类似于令牌桶,它主要由许可发出的速率来定义,如果没有额外的配置,许可证将按每秒许可证规定的固定速度分配,许可将被平滑地分发,若请求超过permitsPerSecond则RateLimiter按照每秒 1/permitsPerSecond 的速率释放许可。

快速开始

项目通过Maven的pom.xml引入。

<dependency>
    <groupId>com.github.wjw465150</groupId>
    <artifactId>rate-limiter-spring-boot-starter</artifactId>
    <version>1.2.0</version>
</dependency>

或者通过Gradle的build.gradle引入

implementation group: 'com.github.wjw465150', name: 'rate-limiter-spring-boot-starter', version: '1.2.0'

使用@RateLimit注解,进行限流

直接在类需要限流的方法上加上注解@RateLimit,进行限流

例如 :

package TestRateLimitStarter;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import org.springframework.stereotype.Component;
import org.wjw.starter.limiter.RateLimit;

@Component
public class MyRateLimitTask {
  @RateLimit(/* 每秒允许的许可数 */ permitsPerSecond = 2)
  void doRunWork1(int i) {
    System.out.println(currentTime() + ": doRunWork1 call execute.." + i);
  }

  @RateLimit(/* 每秒允许的许可数 */ permitsPerSecond = 1,
             /* 此方法每次需要获得许可证的数量,默认是1个 */ permits = 2)
  void doRunWork2(int i) {
    System.out.println(currentTime() + ": doRunWork2 call execute.." + i);
  }

  private String currentTime() {
    LocalDateTime dateTime = LocalDateTime.now();
    return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"));
  }
}

可以写一个SpringBoot的启动类来测试:

/*
 * This Java source file was generated by the Gradle 'init' task.
 */
package TestRateLimitStarter;

import javax.annotation.Resource;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class TestApplication implements CommandLineRunner {
  @Resource
  private MyRateLimitTask limitTask;

  public static void main(String[] args) {
    SpringApplication.run(TestApplication.class, args);
  }

  @Override
  public void run(String... args) throws Exception {
    for (int i = 1; i <= 10; i++) {
      limitTask.doRunWork1(i);
    }
    
    for (int i = 1; i <= 10; i++) {
      limitTask.doRunWork2(i);
    }
    
  }
}

输出如下:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v2.3.10.RELEASE)

2021-10-18 18:20:06.817  INFO 17128 --- [           main] TestRateLimitStarter.TestApplication     : Starting TestApplication on WJW-T14 with PID 17128 (C:\WJW_E\WJW_DATA\OpenSource\SpringBoot-2\eclipse_workspace_rate-limiter\rate-limiter\rate-limiter-test\bin\main started by 86189 in C:\WJW_E\WJW_DATA\OpenSource\SpringBoot-2\eclipse_workspace_rate-limiter\rate-limiter\rate-limiter-test)
2021-10-18 18:20:06.819  INFO 17128 --- [           main] TestRateLimitStarter.TestApplication     : No active profile set, falling back to default profiles: default
2021-10-18 18:20:07.435  INFO 17128 --- [           main] TestRateLimitStarter.TestApplication     : Started TestApplication in 0.849 seconds (JVM running for 1.531)
2021-10-18 06:20:07: doRunWork1 call execute..1
2021-10-18 06:20:07: doRunWork1 call execute..2
2021-10-18 06:20:08: doRunWork1 call execute..3
2021-10-18 06:20:08: doRunWork1 call execute..4
2021-10-18 06:20:09: doRunWork1 call execute..5
2021-10-18 06:20:09: doRunWork1 call execute..6
2021-10-18 06:20:10: doRunWork1 call execute..7
2021-10-18 06:20:10: doRunWork1 call execute..8
2021-10-18 06:20:11: doRunWork1 call execute..9
2021-10-18 06:20:11: doRunWork1 call execute..10
2021-10-18 06:20:11: doRunWork2 call execute..1
2021-10-18 06:20:13: doRunWork2 call execute..2
2021-10-18 06:20:15: doRunWork2 call execute..3
2021-10-18 06:20:17: doRunWork2 call execute..4
2021-10-18 06:20:19: doRunWork2 call execute..5
2021-10-18 06:20:21: doRunWork2 call execute..6
2021-10-18 06:20:23: doRunWork2 call execute..7
2021-10-18 06:20:25: doRunWork2 call execute..8
2021-10-18 06:20:27: doRunWork2 call execute..9
2021-10-18 06:20:29: doRunWork2 call execute..10