1. 前言

微服务中用到了网关的话,自然而然就会考虑网关限流的问题;
当前项目中网关使用的是gateway,而它默认的限流是选择redis的方式来实现限流;

2. 限流方式

3. 项目引入gateway限流

1.引入依赖

<!--redis 用于实现gateway的限流-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
     <!--如果父项目中限定了版本的话,这里不需要再具体制定-->
    <version>2.1.3.RELEASE</version>   
</dependency>

2.springboot入口类中注入KeyResolver ,采用什么方式限流

@Slf4j
@EnableDiscoveryClient
@EnableCircuitBreaker
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class GatewayApplication {
    public static void main(String[] args) throws UnknownHostException {
        ConfigurableApplicationContext application = SpringApplication.run(GatewayApplication.class, args);

    }
	//注入bean
    @Bean
    public KeyResolver ipKeyResolver(){
        return new KeyResolver() {
            @Override
            public Mono<String> resolve(ServerWebExchange exchange) {
            	/**
            	* 限流条件:
            	* 1.用户ip地址(桶是私有)
				* 2.用户用户名(桶是私有)
				* 3.微服的路径(桶是共享的)
				*/
				//此处根据用户的id做为条件限流
                return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
            }
        };
    }

}

3.application.yml文件中配置

其实关键就是在filters中加入name,args的配置,可以对每个服务单独配置;

gateway的redis配置_java

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  redis:
    host: xxx.xx.xx.xx(填写你自己的redis所在主机的ip)
    port: 6379
    password: (如果你的redis配置了密码请加上,没有可省略)
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
#          uri: http://localhost:8001   #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**   #断言,路径相匹配的进行路由
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter #请求数限流 名字不能随便写
              args:
                key-resolver: "#{@ipKeyResolver}"
                redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
                redis-rate-limiter.burstCapacity: 5 #令牌桶总容量
#            - After=2020-09-24T22:18:11.242+08:00[GMT+08:00]
#            - Cookie=username,zzyy
#            - Header=X-Request-Id, \d+   #请求头中要有X-Request-Id属性并且值为整数的正则表达式
#          filters:
#            - AddRequestHeader=X-Request-red, blue

        - id: payment_routh2
#          uri: http://localhost:8001
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**   #断言,路径相匹配的进行路由
          filters:
#            - StripPrefix=1
            - name: RequestRateLimiter #请求数限流 名字不能随便写
              args:
                key-resolver: "#{@ipKeyResolver}"
                redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
                redis-rate-limiter.burstCapacity: 5 #令牌桶总容量

        - id: payment_routh3
          uri: http://news.baidu.com
          predicates:
            - Path=/guonei   #断言,路径相匹配的进行路由


eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

到这里我们就配置好了,只需要启动项目就有限流效果了,测试的时候都设置为1,然后页面我们可以访问来看到限流效果;
但在这里用专业的工具Jmeter来测试会更加能显示限流的功能之强大和控制之精准!
4. 效果测试:

这里我直接贴效果图,如果想知道具体操作,可点击我的另一篇文章具体介绍Jmeter的操作,点击传送门

测试1:

jmeter参数如下图:

gateway的redis配置_限流_02

意思是1秒钟启动10个线程去发起请求,只执行一次;

redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
            redis-rate-limiter.burstCapacity: 5 #令牌桶总容量

桶容量为5个,1秒钟加入一个,那么理论上用已经设置好的jemter请求参数,那就是10个请求应该有6个成功才对;

gateway的redis配置_网关_03

gateway的redis配置_gateway的redis配置_04

测试2:

jmeter参数如下图:

gateway的redis配置_网关_05

意思是3秒钟启动15个线程去发起请求,只执行一次;

redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
           redis-rate-limiter.burstCapacity: 5 #令牌桶总容量

桶容量为5个,1秒钟加入1个,三秒钟就是3个,那么理论上,那就是15个请求应该有5+1*3=8个成功才对;

gateway的redis配置_gateway的redis配置_06

gateway的redis配置_jmeter_07