zoukankan      html  css  js  c++  java
  • Gateway Redis令牌桶请求限流过滤器

    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限流/用户限流)

    package com.mkevin.gateway.config;
    
    import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import reactor.core.publisher.Mono;
    
    /**
     * 限流配置KeyResolver——有三种写法(接口限流/ip限流/用户限流)
     */
    @Configuration
    public class RateLimiteConfig {
    
        /**
         * 接口限流:根据请求路径限流
         * @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
        public KeyResolver 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
        public KeyResolver ipKeyResolver() {
            return exchange -> Mono.just(
                    exchange.getRequest()
                            .getRemoteAddress()
                            .getHostName()
            );
        }
    
        /**
         * 根据请求参数中的userId进行限流
         * 
         * 请求地址写法:http://localhost:8801/rate/123?userId=lisi
         * 
         * @return
         */
        @Bean
        public KeyResolver 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 429 TOO_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 429 TOO_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: 2000
    spring:
      application:
        name: mima-cloud-gateway
      redis:
        database: 1
        host: localhost
        port: 6379
        password:
      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

     

     

     

  • 相关阅读:
    dedecmsV5.7和discuz!X3.4整合之后免激活登陆
    dedecms织梦文章微信分享带缩略图与简介
    关于PHP的mkdir函数
    关于discuz的fap.php 漏洞问题
    discuzX3.4安装之后,没有任何样式怎么办?
    阿里云 RDS for MySQL支持什么引擎
    PHP随机生成要求位数个字符(大小写字母+数字)
    PHP json_decode为什么将json字符串转成数组是对象格式?
    PHP实用的功能函数
    css实现三角形图标
  • 原文地址:https://www.cnblogs.com/linjiqin/p/13633607.html
Copyright © 2011-2022 走看看