SpringCloudGateway--基于redis实现令牌桶算法

目录

一、限流算法

        1、计数器算法

        2、漏桶算法

        3、令牌桶算法

二、Gateway中的限流


一、限流算法

        1、计数器算法

                计数器算法是指从第一个请求开始,每多一个请求就加1,假设设置每秒限流100,当在一秒钟前500ms已经达到100,后面的500ms中的所有请求都会被拒绝。后面500ms的请求被拒绝掉这种现象称为“突刺现象”

        2、漏桶算法

                漏桶算法可以解决“突刺现象”。就是跟生活中漏桶一样,一个水桶,下面有个洞往外漏水,会控制水流速度,不论水桶中有多少睡,漏水的速率保持一致。但是当水到达水桶上限,这时候就不行了。主要是当某时间段有大量请求,但是已经达到漏桶上限的情况。

        3、令牌桶算法

                令牌桶算法是对漏桶算法的一种改进。就是在桶中放入令牌,请求获取到令牌后才能继续执行,如果桶中没有令牌,请求要么继续等待,要么直接拒绝。

                因为令牌是按照一定的速率放置到桶中,所以可以一定程度上解决突发访问。

二、Gateway中的限流

        SpringCloudGateWay项目参考:SpringCloudGateway--自动路由映射与手动路由映射_雨欲语的博客-CSDN博客

       注意需要添加redis依赖包:

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

       算法工厂由代码提供,令牌桶由redis提供,底层逻辑是lua脚本提供,已经封装好的。

       限流实现方式主要是实现KeyResolver类,重写里面的resolve方法:

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;


@Component
public class MyKeyResolver implements KeyResolver {
    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        String hostAddress = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
        return Mono.just(hostAddress);
    }
}

        其中just方法参数表示根据什么限流,这里我使用的是根据ip地址进行限流。

        配置文件:

server:
  port: 9999
spring:
  application:
    name: service-gateway
  cloud: # 配置Spring Cloud相关属性
    gateway:
      discovery: # 配置网关发现机制
        locator: # 配置处理机制
          enabled: false # 开启网关自动映射处理逻辑
          lower-case-service-id: true # 开启小写转换
      filter:
        secure-headers:
          disable:
            - strict-transport-security
            - x-download-options
      routes: # 配置网关中的一个完整路由,包括命名,地址,谓词集合(规则),过滤器集合
        - id: service-one # 路由定义的命名,唯一即可。命名规则符合Java中的变量符命名规则
          uri: lb://service-one # 当前路由定义对应的微服务转发地址,lb - 代表loadbalance
          predicates: # 配置谓词集合
            - Path=/service/**  
          filters:
            - name: RequestRateLimiter
              args:
                keyResolver: '#{@myKeyResolver}' #使用springEL表达式,从spring容器中找对象,并赋值。'#{@beanName}'
                redis-rate-limiter.replenishRate: 1 #生产令牌速度,每秒多少个令牌
                redis-rate-limiter.burstCapacity: 5 # 令牌桶容量

          metadata:
            connect-timeout: 15000 #ms
            response-timeout: 15000 #ms
    nacos:
      username: nacos
      password: nacos
      discovery:
        server-addr: 127.0.0.1
        group: dev
        namespace: dev
        metadata:
          version: v1.0.0
    redis:
      database: 0
      host: ${127.0.0.1}
      port: ${6379}
      password:
      lettuce:
        pool:
          max-active: 80
          max-idle: 80
          min-idle: 1
          max-wait: 5000
          time-between-eviction-runs: 1m
        shutdown-timeout: 10000ms
      timeout: 15000ms


        启动前我们查看redis,keys *:

        可以发现里面此时没有令牌。

        启动项目,然后使用jmeter发送请求测试(jmeter使用方法:Jmeter简单使用_雨欲语的博客-CSDN博客),这里我配置的每秒生产5个令牌,在jmeter中每秒发送10个请求:

        其中失败的请求会返回Too Many Requests,redis查看令牌,可以看到其中本地的ip地址127.0.0.1:

 

猜你喜欢

转载自blog.csdn.net/qq_41061437/article/details/128215153