共计 2512 个字符,预计需要花费 7 分钟才能阅读完成。
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 依赖。
<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
public class GatewayEurekaApplication {public static void main(String[] args) {SpringApplication.run(GatewayEurekaApplication.class, args); | |
} | |
public KeyResolver ipKeyResolver(){// 根据 ip 地址限流 | |
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); | |
} | |
} |
4.3、编写配置文件
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/ | |
spring.redis.database=0 | |
spring.redis.host=192.168.0.201 | |
spring.redis.port=6379 | |
spring.cloud.gateway.routes[0].id=ip_route1 | |
spring.cloud.gateway.routes[0].uri=lb://OPEN-FEIGN | |
spring.cloud.gateway.routes[0].predicates[0]=Path=/hello | |
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 | |
4.4、测试
步骤:
1、启动服务中心
2、启动服务提供者
3、启动服务消费者
4、启动网关工程
5、访问:http://localhost:50024/hello
当快速发送请求时,会进行限流服务不可用
