目录
一、限流算法
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发送请求测试,这里我配置的每秒生产5个令牌,在jmeter中每秒发送10个请求:
其中失败的请求会返回Too Many Requests,redis查看令牌,可以看到其中本地的ip地址127.0.0.1: