文件名称版本号作者qq版本
成功:SpringCloud Gateway限流_RateLimiter_RedisRateLimiterv0.0.1学生宫布8416837SpringBoot 2.2.6
SpringCloud Gateway 2.2.2

配置

yaml
  • 注意看注释
  • 反面教材 [错误的配置],id不对,应该配置在id是微服务的配置大项下面。这样不会起效,按下文修正后,起效了。
spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route # 过滤器名称,不必在意
        uri: https://example.org # 上游,有的地方叫下游-_-||
        predicates:
        	- Path=/xxx/**
        filters:
			- StripPrefix=1
	        - name: RequestRateLimiter # 官方给的名称,对应Java类,有需要再改
	          args:
	            redis-rate-limiter.replenishRate: 10 # 每秒补充10个
	            redis-rate-limiter.burstCapacity: 20 # 突发20个
	            redis-rate-limiter.requestedTokens: 1 # 每次请求消耗1个
	            # rate-limiter: "#{@redisRateLimiter}" # 限流器
	            key-resolver: "#{@userAPIKeyResolver}" # 限流key|字段解析器
  • 正确的
		...
		# 系统模块
        - id: abc-system
          uri: lb://abc-system
          predicates:
            - Path=/system/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1
                redis-rate-limiter.burstCapacity: 2
                key-resolver: "#{@userAPIKeyResolver}"
                # key-resolver: "#{@ipKeyResolver}"
依赖
  • xml
<dependency>
 	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
	<!-- 版本号可以继承父项目或自己写 RELEASE表示最新版-->
	<version>RELEASE</version>
</dependency>
Java
标识
  • user结合API 限流成功

前提是QueryParams携带user参数(一般不会这么做),否则报空指针错误

// 根据什么字段限流,甚至是组合字段
@Bean
public KeyResolver userAPIKeyResolver() {
	// rt,根据字段限流,下文根据Query参数值作为限流标识,请酌情更改为自己的方式
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
    // todo 获取消费者消费的API的id,与user组合
}
  • ip 限流成功 响应码429 服务降级 拒绝服务
/**
     * 功能描述: 基于ip限流
     *
     * @param: []
     * @return: org.springframework.cloud.gateway.filter.ratelimit.KeyResolver
     * @qq: 8416837
     * @author: cc
     * @date: 2020/6/10 11:56
     */
    @Bean("ipKeyResolver")
    public KeyResolver ipKeyResolver() {

        System.out.println("限流解析器");

        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
  • 限流器 Redis限流器(可以省去,可以使用上文的yaml配置代替)
	@Bean
	RedisRateLimiter redisRateLimiter() {
		return new RedisRateLimiter(9, 16); // yaml配置文件已经有了,那么这里就省了。9,16对应replenishRate、burstCapacity
	}
  • 其它key限流

原理一样,使用设置的key存储redis令牌,调用的时候消耗令牌,单位时间内的令牌耗尽则拒绝服务,另外还有个突发流量功能,当突发的时候,令牌会增加,见配置burstCapacity

执行

将配置拷贝到项目或配置中心、代码拷贝到项目,并修改Java代码:KeyResolver
启动项目,使用压测工具压测或者手动发送Http请求,进行测试。

故障

不起效
  • 多线程调用接口,每秒发送10个请求,仍然成功了:
    在这里插入图片描述
分析原因
  • 限流过滤器没有拦截到请求
  • 可能与路由配置有关,回顾路由配置:
		...
		# 限流
        - id: requestratelimiter_route # 过滤器名称,不必在意
          uri: lb://abc-system # 上游,有的地方叫下游-_-||
          predicates:
            - Path=/system/**
          filters:
          - name: RequestRateLimiter # 官方给的名称,对应Java类,有需要再改
            args:
            ...
  • requestratelimiter_route名称是按照官方的,应该没问题;
  • uri表示路由的目标是它,也没问题吧;
  • predicates断言是Path类型,是个正则,当正则匹配访问路径时,即将请求指向目标,好像也没问题;
  • RequestRateLimiter ,没有找到这个类,但是好像找到了相关Bean:
解决方案

1)增加public,KeyResolver userAPIKeyResolver() {改为public KeyResolver userAPIKeyResolver() {
2)限流配置改正确

		# 系统模块
        - id: abc-system
          uri: lb://abc-system
          predicates:
            - Path=/system/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1
                redis-rate-limiter.burstCapacity: 2
                key-resolver: "#{@userAPIKeyResolver}"

限流成功

根据配置进行限流:
在这里插入图片描述
调用接口,限流开始工作,日志
在这里插入图片描述
上图使用多线程模拟10个并发,只有2个请求成功,剩余请求返回429(Too Many Request),说明限流已经ok了,更多细节可以继续优化。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐