通过使用Redisson的RRateLimiter实现对接口的访问限流,这种限流方式属于业务端限流,更加方便,更加灵活,可根据不同的业务进行调整。
Redisson的限流是基于令牌桶算法实现的,除了能够起到限流的作用外,还允许一定程度的流量突发。
使用
1.导入依赖
1 2 3 4 5 6 7 8 9
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.17.5</version> </dependency>
|
2.配置Redisson
RedissonConfig.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import lombok.Data; import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration @ConfigurationProperties(prefix = "spring.redis") @Data public class RedissonConfig { private String host; private Integer port; private String password; private Integer database;
@Bean public RedissonClient redissonClient(){ Config config = new Config(); String redisAddress = "redis://"+host+":"+port;
config.useSingleServer() .setAddress(redisAddress) .setPassword(password) .setDatabase(database);
RedissonClient redisson = Redisson.create(config); return redisson; } }
|
3.测试Redisson
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @SpringBootTest public class RedisTestClass {
@Resource RedissonClient redissonClient;
@Test public void testRedisson() { RList<Object> list = redissonClient.getList("test-list"); list.add("123"); list.add("abcd"); list.add("甲乙丙丁"); System.out.println("rlist:"+list); } }
|
4.封装RedisLimiterManager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| import org.redisson.api.RRateLimiter; import org.redisson.api.RateIntervalUnit; import org.redisson.api.RateType; import org.redisson.api.RedissonClient; import org.springframework.stereotype.Service; import javax.annotation.Resource;
@Service public class RedisLimiterManager {
@Resource RedissonClient redissonClient;
public void doRateLimit(String key){ RRateLimiter rateLimiter = redissonClient.getRateLimiter(key); rateLimiter.trySetRate(RateType.OVERALL, 3, 1, RateIntervalUnit.SECONDS); boolean flag = rateLimiter.tryAcquire(1); if (!flag){ throw new RuntimeException("请求过于频繁"); }
} }
|
5.使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import com.me.bibackend.manager.RedisLimiterManager; import org.junit.jupiter.api.Test; import org.redisson.api.RList; import org.redisson.api.RedissonClient; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.RedisTemplate; import javax.annotation.Resource; import java.util.ArrayList;
@SpringBootTest public class RedisTestClass { @Resource RedisLimiterManager redisLimiterManager;
@Test public void testLimiter() throws InterruptedException { for (int i = 0; i < 5; i++) { new Thread(() -> { redisLimiterManager.doRateLimit("userId+InterfaceName"); System.out.println("成功访问接口"); }).start(); } Thread.sleep(1100); redisLimiterManager.doRateLimit("userId+InterfaceName"); System.out.println("成功访问接口");
Thread.sleep(10000); } }
|
结果
可以看到目前的设定是1秒内对于同一个用户访问某接口只允许访问3次
在第一秒内的5次请求只有前3次成功,而1秒后又重新可以成功访问