基于Redis实现网关限流操作
1.加入Pom依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> <version>2.1.3.RELEASE</version> </dependency>2.声明Bean
//定义一个限流方法 @Bean public KeyResolver ipkeyResolver(){ return new KeyResolver() { @Override public Mono<String> resolve(ServerWebExchange exchange) { ServerHttpRequest request = exchange.getRequest(); String hostName = request.getRemoteAddress().getHostName(); return Mono.just(hostName); } }; }3.在application.yml的路由模块中添加配置文件和Redis主机信息
routes: - id: goods uri: lb://order predicates: - Path=/order/** filters: - StripPrefix= 1 #限流配置 - name: RequestRateLimiter #请求数限流 名字不能随便写 args: key-resolver: "#{@ipkeyResolver}" #引用Bean redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率 redis-rate-limiter.burstCapacity: 1 #令牌桶总容量 #限流end redis: host: 192.168.200.253测试:错误码 429
番外篇:Redis实现限流的三种方式
第一种:基于Redis的setNx操作
我们需要在10秒内限定20个请求,那么我们在setnx的时候可以设置过期时间10,当请求的setnx数量达到20时候即达到了限流效果第二种:基于Redis的数据结构zset
/*我们可以将请求打造成一个zset数组,当每一次请求进来的时候,value保持唯一,可以用UUID生成,而score可以用当前时间戳表示,因为score我们可以用来计算当前时间戳之内有多少的请求数量。而zset数据结构也提供了range方法让我们可以很轻易的获取到2个时间戳内有多少请求 */ public Response limitFlow(){ Long currentTime = new Date().getTime(); System.out.println(currentTime); if(redisTemplate.hasKey("limit")) { Integer count = redisTemplate.opsForZSet().rangeByScore("limit", currentTime - intervalTime, currentTime).size(); // intervalTime是限流的时间 System.out.println(count); if (count != null && count > 5) { return Response.ok("每分钟最多只能访问5次"); } } redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime); return Response.ok("访问成功");第三种:基于Redis的令牌桶算法
依靠List的leftPop来获取令牌
// 输出令牌 public Response limitFlow2(Long id){ Object result = redisTemplate.opsForList().leftPop("limit_list"); if(result == null){ return Response.ok("当前令牌桶中无令牌"); } return Response.ok(articleDescription2); }依靠Java的定时任务,定时往List中rightPush令牌
// 10S的速率往令牌桶中添加UUID,保证唯一性 @Scheduled(fixedDelay = 10_000,initialDelay = 0) public void setIntervalTimeTask(){ redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());