限流措施

2022-09-15 14:18:47 浏览数 (1)

1、为什么要限流

一般而言,正常的流量越多越好,比如用户快速增长、热点事件带来的蜂拥的人流。但在实际的网络流量中,除正常的流量外,还有很多非正常的流量,比如网络攻击、恶意爬虫。所以在高并发的应用中,需要通过限流来保障服务对所有用户的可用性。限流和缓存、降级一样,也是保护高并发系统的利器。

2、常见的限流措施

高并发系统常采用以下限流措施

  • 限制总并发数。如,数据库连接池,线程池
  • 限制瞬时并发数。如,Nginx的limit_conn模块可以限制瞬时并发连接数
  • 限制时间窗口内的平均速率。如,Nginx的limit_req模块
  • 限制消息中间件的消费速率
  • 限制远程接口的调用速率
  • 限制每秒的平均速率
  • 对线程池进行隔离。如果超过线程池的负载,则进行熔断
  • 通过Tomcat容器限制线程数来控制并发

一般限流都在网关层实现,比如使用Nginx、Zuul、Spring Cloud Gateway、Openresty、Kong等。

3、限流算法

3.1、计算器算法

算法原理:从第一个请求进来开始计时,在接下来时间内(如1s),每来一个请求就把计数加1;如果累加的数字达到了设定的值,则后续的请求就会被全部拒绝;等单位时间结束后把计数恢复为0,重新开始计数。

3.2、漏桶算法

算法原理:把请求先放入漏桶里等待,然后漏桶以一定的速度处理进入漏桶中的请求;如果请求的进入速度过大,则导致漏桶装不下请求而拒绝后续的请求。

3.3、令牌桶算法

令牌桶算法和现在各大机构使用的叫号机很类似:当请求到达时,先去令牌桶中取一个令牌,然后等响应。

4、用Spring Cloud Gateway内置的限流工厂实现限流

4.1、添加依赖

Spring Cloud Gateway内置了限流工厂"RequestRateLimiterGatewayFilterFactory",它底层是使用Redis的Lua脚本实现的,所以在添加好Spring Cloud Gateway依赖后还需要添加Redis依赖。

代码语言:javascript复制
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

4.2、修改启动项,添加IP地址限流的Bean

代码语言:javascript复制
@SpringBootApplication
public class GatewayEurekaApplication {


    public static void main(String[] args) {
        SpringApplication.run(GatewayEurekaApplication.class, args);
    }
    
    @Bean
    public KeyResolver ipKeyResolver(){
        //根据ip地址限流
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
}

4.3、编写配置文件

代码语言:javascript复制
spring.application.name=gateway-eureka
server.port=50024
#注册中心地址
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=true
eureka.client.service-url.defaultZone=http://eureka01:50025/eureka/,http://eureka02:50026//eureka/
#Redis数据库索引(默认为0)
spring.redis.database=0
#redis服务器ip地址
spring.redis.host=192.168.0.201
spring.redis.port=6379
#Redis服务器的连接密码(默认为空)
#id:自定义路由ID
spring.cloud.gateway.routes[0].id=ip_route1
#uri:目标服务地址
spring.cloud.gateway.routes[0].uri=lb://OPEN-FEIGN
#predicates:路由条件。Predicate根据输入参数返回一个布尔值。其包含多种默认方法来将Predicate组合成复杂的路由逻辑
spring.cloud.gateway.routes[0].predicates[0]=Path=/hello
# 限流过滤器使用gateway内置令牌算法
spring.cloud.gateway.routes[0].filters[0].name=RequestRateLimiter
#令牌补充的频率,每次就一个
spring.cloud.gateway.routes[0].filters[0].args.redis-rate-limiter.replenishRate=1
#令牌桶的最大容量,允许在一秒钟内完成的最大请求数
spring.cloud.gateway.routes[0].filters[0].args.redis-rate-limiter.burstCapacity=2
#用于限流的键的解析器的Bean对象的名字。它使用SpEL表达式根据#{@beanName}从Spring 容器中获取Bean对象。在yml配置文件中需要用双引号包裹。
spring.cloud.gateway.routes[0].filters[0].args.key-resolver=#{@ipKeyResolver}

4.4、测试

步骤:

1、启动服务中心

2、启动服务提供者

3、启动服务消费者

4、启动网关工程

5、访问:http://localhost:50024/hello

当快速发送请求时,会进行限流服务不可用

0 人点赞