这篇文章,主要介绍微服务组件之Gateway实现服务限流(计数器算法、漏桶算法、令牌桶算法)。
目录
一、服务限流
1.1、几种限流算法
(1)计数器算法
(2)漏桶算法
(3)令牌桶算法
1.2、Gateway实现服务限流
(1)引入依赖
(2)添加配置信息
(3)指定令牌生成方式
(4)运行测试
一、服务限流
1.1、几种限流算法
限流就是指:限制服务的请求量,客户端每秒钟发起的HTTP请求数量(QPS,Queries Per Second),表示每秒钟的查询数量。为了能避免大量请求堆积,从而导致服务器宕机,所以就需要对请求进行限流操作。常见的限流算法有下面这些:
- 计数器算法(Counter)。
- 漏桶算法(Leaky Bucket)。
- 令牌桶算法(Token Bucket)。
(1)计数器算法
计数器算法是指:设置一个计数器,当在指定的时间范围里面,某个接口有访问则将计数器加1,当计数器达到最大值,并且此时是在这个时间范围里面,那么此时就对这个接口进行限流操作。
这种算法虽然实现简单,但是存在一个问题,那就是如果在结束时间和下一次开始时间之间,刚好来了大量请求,那么此时就是1秒出现大量请求,有可能导致服务崩溃。
(2)漏桶算法
漏桶算法,是指:大量请求可以到达,但是这些请求会首先进入一个地方,我们这个地方叫做:桶,请求来了就放入桶里面,然后每次这个桶就分发一个请求给对应的微服务,从而实现限流操作。
这种算法虽然能够控制请求量,但是也有问题,那就是如果大量请求同时达到Gateway,那么Gateway可能会出现宕机情况,此外由于每次都是从桶中分发一个请求到下游系统,如果下游系统每次能够处于200个请求,显示浪费了下游系统的资源。
(3)令牌桶算法
令牌桶算法,是对漏桶算法的一个改进,它的思想是:对每次请求都需要获取一个令牌,只要拿到令牌的请求才能够继续执行,没有拿到令牌的请求,要么被阻塞,要么快速失败,令牌桶算法会有一个桶专门用于保存令牌,这个令牌会按照规则自动生成并放入令牌桶里面。
令牌桶算法是最优的一种限流算法,Gateway中的限流算法就是采用了令牌桶算法,支持三种令牌桶算法:基于URI限流、基于请求参数限流、基于IP限流。
1.2、Gateway实现服务限流
Gateway中提供的限流是采用的令牌桶算法,并且基于Redis + LUA脚本实现的限流,所以这里需要引入redis的依赖。
(1)引入依赖
- 在gateway工程中,引入redis依赖、gateway依赖。
<!-- 引入 Gateway 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 引入 redis 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<!-- 引入 commons-pool 连接池依赖 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
(2)添加配置信息
在application.yml配置文件中,添加如下内容:
server:
port: 8888
spring:
application:
name: gateway-limiting
# 配置 gateway 路由信息
cloud:
gateway:
# 指定路由信息
routes:
- id: consumer-client # 路由唯一标识,一般和微服务应用名称相同即可
# 目标路由的服务地址,这里采用的是静态路由(将微服务的地址写死在配置文件里面)
uri: http://localhost:8081/
# 配置断言,也就是请求的URI满足哪些规则,才可以匹配当前这个routes路由信息
predicates:
# 这里使用路由断言
- Path=/**
filters:
# 指定限流过滤器
- name: RequestRateLimiter
args:
# 基于令牌桶算法,生成令牌的速率
redis-rate-limiter.replenishRate: 1
# 令牌桶的最大容量
redis-rate-limiter.burstCapacity: 2
# 指定生成令牌的算法解析策略,这里是使用了SpEL表达式,获取寻找名字是 keyResolver 的bean对象
key-resolver: "#{@keyResolver}"
# redis 配置
redis:
host: 127.0.0.1
port: 6379
database: 0
lettuce:
pool:
max-active: 1024
max-wait: 10000
max-idle: 200
min-idle: 5
(3)指定令牌生成方式
Gateway中可以有多种限流策略,例如:通过URI进行限流、通过请求参数限流、通过IP地址限流。要是有哪一种限流策略,只需要修改对应的KeyResolver即可。
package com.gitee.demo.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* @version 1.0.0
* @Date: 2023/4/20 14:16
* @Copyright (C) ZhuYouBin
* @Description: 令牌桶算法中,令牌的生成算法
*/
@Configuration
public class KeyResolverConfiguration {
@Bean
public KeyResolver keyResolver() {
return new KeyResolver() {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
// 这里根据请求【URI】进行限流
return Mono.just(exchange.getRequest().getPath().toString());
}
};
}
// @Bean
// public KeyResolver keyResolver() {
// return new KeyResolver() {
// @Override
// public Mono<String> resolve(ServerWebExchange exchange) {
// // 这里根据请求【请求参数username】进行限流
// return Mono.just(exchange.getRequest().getQueryParams().getFirst("username"));
// }
// };
// }
//
// @Bean
// public KeyResolver keyResolver() {
// return new KeyResolver() {
// @Override
// public Mono<String> resolve(ServerWebExchange exchange) {
// // 这里根据请求【IP地址】进行限流
// return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
// }
// };
// }
}
- 注意:KeyResolver只能够存在一个Bean对象。
(4)运行测试
启动redis服务、启动网关工程、启动消费者工程,浏览器访问某个接口,测试是否限流成功。假设现在是采用URI限流模式,并且配置文件中设置的是最大允许2个请求同时访问,超过2个请求,就会报错,客户端就会接收到【HTTP ERROR 429】的响应结果,这表示被限流了。
到此,Gateway服务限流就介绍完啦。
综上,这篇文章结束了,主要介绍微服务组件之Gateway实现服务限流(计数器算法、漏桶算法、令牌桶算法)。