springcloud-gateway限流
小伙伴们,你们好呀!我是老寇!一起学习学习gateway限流
一、常见限流算法
1.漏桶算法(不推荐)
1.原理:将请求缓存到一个队列中,然后以固定的速度处理,从而达到限流的目的
2.实现:将请求装到一个桶中,桶的容量为固定的一个值,当桶装满之后,就会将请求丢弃掉,桶底部有一个洞,以固定的速率流出。
3.举例:桶的容量为1W,有10W并发请求,最多只能将1W请求放入桶中,其余请求全部丢弃,以固定的速度处理请求
4.缺点:处理突发流量效率低(处理请求的速度不变,效率很低)
2.令牌桶算法(推荐)
1.原理:将请求放在一个缓冲队列中,拿到令牌后才能进行处理
2.实现:装令牌的桶大小固定,当令牌装满后,则不能将令牌放入其中;每次请求都会到桶中拿取一个令牌才能放行,没有令牌时即丢弃请求/继续放入缓存队列中等待
3.举例:桶的容量为10w个,生产1w个/s,有10W的并发请求,以每秒10W个/s速度处理,随着桶中的令牌很快用完,速度又慢慢降下来啦,而生产令牌的速度趋于一致1w个/s
4.缺点:处理突发流量提供了系统性能,但是对系统造成了一定的压力,桶的大小不合理,甚至会压垮系统(处理1亿的并发请求,将桶的大小设置为1,这个系统一下就凉凉啦)
二、网关限流(springcloud gateway + redis实战)
1.pom.xml配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
2.yaml配置
spring:
application:
name: laokou-gateway
cloud:
gateway:
routes:
- id: LAOKOU-SSO-DEMO
uri: lb://laokou-sso-demo
predicates:
- Path=/sso/**
filters:
- StripPrefix=1
- name: RequestRateLimiter #请求数限流,名字不能乱打
args:
key-resolver: "#{@ipKeyResolver}"
redis-rate-limiter.replenishRate: 1 #生成令牌速率-设为1方便测试
redis-rate-limiter.burstCapacity: 1 #令牌桶容量-设置1方便测试
redis:
database: 0
cluster:
nodes: x.x.x.x:7003,x.x.x.x:7004,x.x.x.x:7005,x.x.x.x:7003,x.x.x.x:7004,x.x.x.x:7005
password: laokou #密码
timeout: 6000ms #连接超时时长(毫秒)
jedis:
pool:
max-active: -1 #连接池最大连接数(使用负值表示无极限)
max-wait: -1ms #连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 #连接池最大空闲连接
min-idle: 5 #连接池最小空间连接
3.创建bean
@Bean(value = "ipKeyResolver")
KeyResolver ipKeyResolver() {
return exchange -> {
String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
log.info("ip:{}",ip);
return Mono.just(ip);
};
}
三、测试限流(编写java并发测试)
@Slf4j
public class HttpUtil {
public static void apiConcurrent(String url,Map<String,String> params) {
Integer count = 200;
//创建线程池
ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 200, 0L, TimeUnit.SECONDS, new SynchronousQueue<>());
//同步工具
CountDownLatch latch = new CountDownLatch(count);
Map<String,String> dataMap = new HashMap<>(1);
dataMap.put("authorize","XXXXXXX");
for (int i = 0; i < count; i++) {
pool.execute(() -> {
try {
//访问网关的API接口
HttpUtil.doGet("http://localhost:1234/sso/laokou-demo/user",dataMap);
} catch (IOException e) {
e.printStackTrace();
}finally {
latch.countDown();
}
});
}
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static String doGet(String url, Map<String, String> params) throws IOException {
//创建HttpClient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
String resultString = "";
CloseableHttpResponse response = null;
try {
//创建uri
URIBuilder builder = new URIBuilder(url);
if (!params.isEmpty()) {
for (Map.Entry<String, String> entry : params.entrySet()) {
builder.addParameter(entry.getKey(), entry.getValue());
}
}
URI uri = builder.build();
//创建http GET请求
HttpGet httpGet = new HttpGet(uri);
List<NameValuePair> paramList = new ArrayList<>();
RequestBuilder requestBuilder = RequestBuilder.get().setUri(new URI(url));
requestBuilder.setEntity(new UrlEncodedFormEntity(paramList, Consts.UTF_8));
httpGet.setHeader(new BasicHeader("Content-Type", "application/json;charset=UTF-8"));
httpGet.setHeader(new BasicHeader("Accept", "*/*;charset=utf-8"));
//执行请求
response = httpClient.execute(httpGet);
//判断返回状态是否是200
if (response.getStatusLine().getStatusCode() == 200) {
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
}
} catch (Exception e) {
log.info("调用失败:{}",e);
} finally {
if (response != null) {
response.close();
}
httpClient.close();
}
log.info("打印:{}",resultString);
return resultString;
}
}
说明这个网关限流配置是没有问题的
作者:k↑
来源链接:https://blog.csdn.net/qq_39893313/article/details/117635759