Gateway Redis令牌桶请求限流过滤器

摘要:
springcloudgateway默认基于redis令牌桶算法进行微服务的限流保护,采用RateLimter限流算法来实现。

spring cloud gateway默认基于redis令牌桶算法进行微服务的限流保护,采用RateLimter限流算法来实现。

1.引入依赖包

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency> 
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

2、yml中配置redis

spring:
  application:
    name: mima-cloud-gateway
  redis:
    database: 1
    host: localhost
    port: 6379
    password:

3、配置KeyResolver——RateLimiteConfig.java(接口限流/ip限流/用户限流)

packagecom.mkevin.gateway.config;

importorg.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.context.annotation.Primary;
importreactor.core.publisher.Mono;

/*** 限流配置KeyResolver——有三种写法(接口限流/ip限流/用户限流)
 */@Configuration
public classRateLimiteConfig {

    /*** 接口限流:根据请求路径限流
     * @return
     */
    /*如果不使用@Primary注解,会报如下错误,需要注意
    Description:
    Parameter 1 of method requestRateLimiterGatewayFilterFactory in org.springframework.cloud.gateway.config.GatewayAutoConfiguration required a single bean, but 3 were found:
            - pathKeyResolver: defined by method 'pathKeyResolver' in class path resource [com/mkevin/gateway/config/RateLimiteConfig.class]
            - ipKeyResolver: defined by method 'ipKeyResolver' in class path resource [com/mkevin/gateway/config/RateLimiteConfig.class]
            - userKeyResolver: defined by method 'userKeyResolver' in class path resource [com/mkevin/gateway/config/RateLimiteConfig.class]
    Action:
    Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier
    to identify the bean that should be consumed
    */@Bean
    @Primary
    publicKeyResolver pathKeyResolver() {
        //写法1
       return exchange ->Mono.just(
                exchange.getRequest()
                        .getPath()
                        .toString()
        );

        /*//写法2
        return new KeyResolver() {
            @Override
            public Mono<String> resolve(ServerWebExchange exchange) {
                return Mono.just(exchange.getRequest()
                        .getPath()
                        .toString());
            }
        };
        */}

    /*** 根据请求IP限流
     * @return
     */@Bean
    publicKeyResolver ipKeyResolver() {
        return exchange ->Mono.just(
                exchange.getRequest()
                        .getRemoteAddress()
                        .getHostName()
        );
    }

    /*** 根据请求参数中的userId进行限流
     * 
     * 请求地址写法:http://localhost:8801/rate/123?userId=lisi
     * 
     * @return
     */@Bean
    publicKeyResolver userKeyResolver() {
        return exchange ->Mono.just(
                exchange.getRequest()
                        .getQueryParams()
                        .getFirst("userId")
        );
    }
}

4、yml中配置spring.cloud.gateway.routes.filters

spring:
  cloud:
    gateway:
      routes:
        - id: rate-limit-demo
          uri: lb://mima-cloud-producer
predicates:
            #访问路径:http://localhost:8801/rate/123
            - Path=/rate/**filters:
            - name: RequestRateLimiter
              args:
                # 令牌桶每秒填充平均速率, 允许用户每秒处理多少个请求。
                redis-rate-limiter.replenishRate: 1
                # 令牌桶的容量,允许在1s内完成的最大请求数。
                redis-rate-limiter.burstCapacity: 2
                # 使用SpEL表达式从Spring容器中获取Bean对象, 查看RateLimiteConfig实现类中的方法名
                key-resolver: "#{@pathKeyResolver}"
                #key-resolver: "#{@ipKeyResolver}"
                #key-resolver: "#{@userKeyResolver}"

5、访问地址测试
http://localhost:8801/rate/123

当F5频繁刷新请求接口时,控制台会报429错误状态码,提示我们请求过多,如下:

[开始]请求路径:/rate/123[应答]请求路径:/rate/123耗时:2ms
2020-09-08 16:23:27.253 DEBUG 18512 --- [ioEventLoop-4-1] o.s.w.s.adapter.HttpWebHandlerAdapter    : [62eb90e0] Completed 429TOO_MANY_REQUESTS
2020-09-08 16:23:27.394 DEBUG 18512 --- [ctor-http-nio-2] o.s.w.s.adapter.HttpWebHandlerAdapter    : [62eb90e0] HTTP GET "/rate/123"corsFilter... run
[开始]请求路径:/rate/123[应答]请求路径:/rate/123耗时:2ms
2020-09-08 16:23:27.397 DEBUG 18512 --- [ioEventLoop-4-1] o.s.w.s.adapter.HttpWebHandlerAdapter    : [62eb90e0] Completed 429TOO_MANY_REQUESTS
2020-09-08 16:23:27.536 DEBUG 18512 --- [ctor-http-nio-2] o.s.w.s.adapter.HttpWebHandlerAdapter    : [62eb90e0] HTTP GET "/rate/123"corsFilter... run

6、当发生限流时,会向redis中存储两个数据

127.0.0.1:1>keys *
 1)  "request_rate_limiter.{/rate/123}.timestamp"
 2)  "request_rate_limiter.{/rate/123}.tokens"
 
127.0.0.1:1>keys *
 1)  "request_rate_limiter.{0:0:0:0:0:0:0:1}.timestamp"
 2)  "request_rate_limiter.{0:0:0:0:0:0:0:1}.tokens"
 
127.0.0.1:1>keys *
 1)  "request_rate_limiter.{lisi}.timestamp"
 2)  "request_rate_limiter.{lisi}.tokens"

参数说明:
request_rate_limiter.{key}.timestamp:
存储的是当前时间的秒数,也就是System.currentTimeMillis()/1000或者Instant.now().getEpochSecond()。

request_rate_limiter.{key}.tokens:
存储的是当前这秒钟对应的可用令牌数量

7、完整yml配置文件

# 开启resilience4j断路器
# spring.cloud.circuitbreaker.resilience4j.enabled: true# 设置hystrix断路器超时时间
# hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 2000spring:
  application:
    name: mima-cloud-gateway
  redis:
    database: 1host: localhost
    port: 6379password:
  cloud:
    gateway:
      routes:
        - id: rate-limit-demo
          uri: lb://mima-cloud-producer
predicates:
            #访问路径:http://localhost:8801/rate/123
            - Path=/rate/**filters:
            - name: RequestRateLimiter
              args:
                # 令牌桶每秒填充平均速率, 允许用户每秒处理多少个请求。
                redis-rate-limiter.replenishRate: 1
                # 令牌桶的容量,允许在1s内完成的最大请求数。
                redis-rate-limiter.burstCapacity: 2
                # 使用SpEL表达式从Spring容器中获取Bean对象, 查看RateLimiteConfig实现类中的同名方法
                #key-resolver: "#{@pathKeyResolver}"
                #key-resolver: "#{@ipKeyResolver}"
                #请求地址写法:http://localhost:8801/rate/123?userId=lisi
                key-resolver: "#{@userKeyResolver}"

#  The RequestRateLimiter GatewayFilter Factory
#  The Redis RateLimiter
#  Modify a Request Body GatewayFilter Factory 测试版本,未来可能改动
#  Modify a Response Body GatewayFilter Factory 测试版本,未来可能改动

server:
  port: 8801
eureka:
  client:
    serviceUrl:
      #defaultZone: http://kevin:123456@localhost:8761/eureka/
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
    #instance-id: ${spring.application.name}:${spring.cloud.client.ip-address:}:${server.port}
    instance-id: ${spring.application.name}:${server.port}
debug: true
management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always
    shutdown: true

免责声明:文章转载自《Gateway Redis令牌桶请求限流过滤器》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇互联网金融借款违约预测etcd 开启auth认证下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Redis在Linux下的安装

一、下载地址 ①redis中文网下载地址:http://www.redis.cn/ ②百度云网盘下载地址:https://pan.baidu.com/s/1UQcF9V3lwA0fxquM_JFMZw 提取码:lnwk 二、编译软件安装 yum -y install gcc gcc-c++ make 三、安装 解压后进入目录,编译安装命令: make ma...

SpringBoot2.x 整合Spring-Session实现Session共享

SpringBoot2.x 整合Spring-Session实现Session共享 1.前言 发展至今,已经很少还存在单服务的应用架构,不说都使用分布式架构部署, 至少也是多点高可用服务。在多个服务器的情况下,Seession共享就是必须面对的问题了。 解决Session共享问题,大多数人的思路都是比较清晰的, 将需要共享的数据存在某个公共的服务中,如缓存...

PHP操作Redis数据库常用方法

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。 Redis支持的数据类型有 Stirng(字符串), List(列表), Hash(字典), Set(集合), Sorted Set(有序集合); 要让php能用上redis,首先就得安装redis扩展。 1.安装re...

Redis过期设置

Redis支持按key设置过期时间,过期后值将被删除(在客户端看来是补删除了的) 用TTL命令可以获取某个key值的过期时间(-1表示永不过期) 127.0.0.1:6379> set name "ghj1976" OK 127.0.0.1:6379> ttl name (integer) -1 TTL key 以秒为单位,返回给定 key...

spring cloud gateway 日志打印

从api请求中获取访问的具体信息,是一个很常见的功能,这几天在研究springcloud,使用到了其中的gateway,刚好将研究的过程结果都记录下来 0. Version <parent> <groupId>org.springframework.boot</groupId> <artifact...

SpringBoot入门-Redis(六)

依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId>...