【教程】SpringCloud+Nacos+Feign+Gateway ( 八 ) Nacos-Gateway 网关 限流

【教程】SpringCloud+Nacos+Feign+Gateway ( 八 ) Nacos-Gateway 网关 限流

 

从某种意义上讲,令牌桶算法是对漏桶算法的一种改进,桶算法能够限制请求调用的速率,而令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用。在令牌桶算法中,存在一个桶,用来存放固定数量的令牌。算法中存在一种机制,以一定的速率往桶中放令牌。每次请求调用需要先获取令牌,只有拿到令牌,才有机会继续执行,否则选择选择等待可用的令牌、或者直接拒绝。放令牌这个动作是持续不断的进行,如果桶中令牌数达到上限,就丢弃令牌,所以就存在这种情况,桶中一直有大量的可用令牌,这时进来的请求就可以直接拿到令牌执行,比如设置qps为100,那么限流器初始化完成一秒后,桶中就已经有100个令牌了,这时服务还没完全启动好,等启动完成对外提供服务时,该限流器可以抵挡瞬时的100个请求。所以,只有桶中没有令牌时,请求才会进行等待,最后相当于以一定的速率执行。

 

 

 

 

1 增加依赖

    <!-- 限流Redis实现 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>

    <!-- redis -->
    <dependency>
      <groupId>com.gw</groupId>
      <artifactId>gwcloud-starter-redis</artifactId>
    </dependency>

 

2 增加配置application.yml

核心配置

  # 连接Redis配置
  redis:
    host: redis-server-02
    port: 6379
    database: 0
    password: ******
          filters:
              # 熔断器
            - name: Hystrix
              args:
                name: fallbackCmd
                fallbackUri: 'forward:/fallbackCmd'
            ## 限流
            - name: RequestRateLimiter
              args:
                ### 限流过滤器的 Bean 名称   #用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象  对应com.gw.module.gateway.config.RateLimiterConfiguration.apiKeyResolver
                key-resolver: '#{@apiKeyResolver}'
                ### 希望允许用户每秒处理多少个请求  #令牌桶每秒填充平均速率
                redis-rate-limiter.replenishRate: 1
                ### 用户允许在一秒钟内完成的最大请求数  #令牌桶总容量
                redis-rate-limiter.burstCapacity: 100

完整配置

server:
  # 端口
  port: 9999

spring:
  application:
    # 应用名称
    name: gwcloud-module-gateway
  # 连接Redis配置
  redis:
    host: redis-server-02
    port: 6379
    database: 0
    password: ******
  cloud:
    # 网关配置
    gateway:
      discovery:
        locator:
          # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
          # 开启从注册中心动态创建路由的功能
          enabled: true
      globalcors:
        cors-configurations:
          '[/**]':
            allowCredentials: true
            allowedOrigins: "*"
            allowedMethods: "*"
            allowedHeaders: "*"
      #如果启用nacos或者数据库配置请删除以下配置
      # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
      routes:
          #路由标识(id:标识,具有唯一性)   简单尝试
        - id: gwcloud-user-provide-service
          # 目标服务地址(uri:地址,请求转发后的地址)   lb://服务名
          # lb协议表示启用负载均衡功能,然后后面跟着微服务名称
          uri: lb://gwcloud-user-provide-service
          # 路由条件(predicates:断言,匹配 HTTP 请求内容)
          predicates:
              ## 转发地址格式为 uri/nacos-config/**
            - Path=/nacos-config/**
#              转发地址格式为 uri/nacos-config
#            - Path=/nacos-config
          filters:
              # 熔断器
            - name: Hystrix
              args:
                name: fallbackCmd
                fallbackUri: 'forward:/fallbackCmd'
            ## 限流
            - name: RequestRateLimiter
              args:
                ### 限流过滤器的 Bean 名称   #用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象  对应com.gw.module.gateway.config.RateLimiterConfiguration.apiKeyResolver
                key-resolver: '#{@apiKeyResolver}'
                ### 希望允许用户每秒处理多少个请求  #令牌桶每秒填充平均速率
                redis-rate-limiter.replenishRate: 1
                ### 用户允许在一秒钟内完成的最大请求数  #令牌桶总容量
                redis-rate-limiter.burstCapacity: 100

          #路由标识(id:标识,具有唯一性)   简单尝试
        - id: gwcloud-user-provide-service
          # 目标服务地址(uri:地址,请求转发后的地址)   lb://服务名
          uri: lb://gwcloud-user-provide-service
          # 路由条件(predicates:断言,匹配 HTTP 请求内容)
          predicates:
              ## 通过请求参数过滤
            - Query=token
      # 全局 filters
      default-filters:
          # 全局熔断降级配置
        - name: Hystrix
          args:
            name: default
            ### fallback 时调用的方法 http://localhost:9999/fallback
            fallbackUri: 'forward:/fallback'

# 这种熔断只能针对服务网关调用后端服务接口超时才会生效,后端服务抛异常无效
# hystrix 信号量隔离, default-全局默认-60秒后自动超时
hystrix:
  enabled: true
  shareSecurityContext: true
  command:
    default:  # 默认
      execution:
        isolation:
          # 隔离策略 THREAD以及SEMAPHORE
          # THREAD:当隔离策略为 THREAD 时,是没办法拿到 ThreadLocal 中的值的
          strategy: SEMAPHORE
          thread:
            timeoutInMilliseconds: 60000
    fallbackCmd:
      execution:
        isolation:
#          strategy: SEMAPHORE
          thread: # 60秒没响应自动熔断 跳转到配置的fallbackUri
            timeoutInMilliseconds: 60000

 

3.核心代码

package com.gw.module.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;

/**
 * @Title: 限流配置类
 * @Description: 描述
 * @Version: v1.0
 * @Author: Mr.Guan
 * @Mail GuanWeiMail@163.com
 * @DateTime: 2021-03-08
 * @Project springcloud-gw-parent
 * @Package com.gw.module.gateway.config
 */
@Configuration
public class RateLimiterConfiguration {


    /**
     * IP限流 (通过exchange对象可以获取到请求信息,这边用了HostName)
     */
    @Bean
    @Primary
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
    }

    /**
     * 用户限流 (通过exchange对象可以获取到请求信息,获取当前请求的用户 TOKEN)
     */
    @Bean
    public KeyResolver userKeyResolver() {
        //使用这种方式限流,请求Header中必须携带X-Access-Token参数
        return exchange -> Mono.just(exchange.getRequest().getHeaders().getFirst("GlobalAccessTokenFilter.X_ACCESS_TOKEN"));
    }


    /**
     * 接口限流 (获取请求地址的uri作为限流key)
     */
    @Bean
    public KeyResolver apiKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }

    /**
     * 参数限流
     * @return
     */
    @Bean
    public KeyResolver paramsKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
    }


}

 

4 测试  借助 Jmeter

参考:https://blog.csdn.net/G971005287W/article/details/105258275

https://blog.csdn.net/G971005287W/article/details/114537942

 

 

64%的请求被拦截

 

 

 

 

 

 

 

 

 

 

 

 

 

 


版权声明:本文为G971005287W原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。