x目录
一,漏桶算法
漏桶算法可以很好地限制容量池的大小,从而防止流量暴增。漏桶可以看作是一个带有常量服务时间的 单服务器队列,如果漏桶(包缓存)溢出,那么数据包会被丢弃。 在网络中,漏桶算法可以控制端口的 流量输出速率,平滑网络上的突发流量,实现流量整形,从而为网络提供一个稳定的流量。
为了更好的控制流量,漏桶算法需要通过两个变量进行控制:一个是桶的大小,支持流量突发增多时可 以存多少的水(burst),另一个是水桶漏洞的大小(rate)。
漏桶算法可以限制请求速度
二,令牌桶算法
令牌桶算法是对漏桶算法的一种改进,桶算法能够限制请求调用的速率,而令牌桶算法能够在限制调用 的平均速率的同时还允许一定程度的突发调用。在令牌桶算法中,存在一个桶,用来存放固定数量的令 牌。算法中存在一种机制,以一定的速率往桶中放令牌。每次请求调用需要先获取令牌,只有拿到令 牌,才有机会继续执行,否则选择选择等待可用的令牌、或者直接拒绝。放令牌这个动作是持续不断的 进行,如果桶中令牌数达到上限,就丢弃令牌,所以就存在这种情况,桶中一直有大量的可用令牌,这 时进来的请求就可以直接拿到令牌执行,比如设置qps为100,那么限流器初始化完成一秒后,桶中就 已经有100个令牌了,这时服务还没完全启动好,等启动完成对外提供服务时,该限流器可以抵挡瞬时 的100个请求。所以,只有桶中没有令牌时,请求才会进行等待,最后相当于以一定的速率执行。
三,基于Filter的限流
SpringCloudGateway官方就提供了基于令牌桶的限流支持。基于其内置的过滤器工厂 RequestRateLimiterGatewayFilterFactory 实现。在过滤器工厂中是通过Redis和lua脚本结合的方 式进行流量控制。
3.1 环境搭建
在springCloud getway 模块 导入redis 依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--监控依赖-->
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>-->
<!--redis 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
</dependencies>
3.2 启动redis
启动redis ,并且点击redis -cli.exe 文件,后,输入monitor,就可以开启redis 监听,当我们访问接口时,有监听了才是正常的,不然启动网关限流无效。
修改application.yml配置文件,在application.yml配置文件中加入限流的配置,代码如下:
server:
port: 8080 #端口
spring:
application:
name: api-gateway-server #服务名称
redis:
host: localhost
pool: 6379
database: 0
cloud: #配置SpringCloudGateway的路由
gateway:
routes:
- id: service-product
uri: lb://service-product
predicates:
- Path=/service-product/**
filters:
- name: RequestRateLimiter
args:
# 使用SpEL从容器中获取对象
key-resolver: '#{@pathKeyResolver}'
# 令牌桶每秒填充平均速率
redis-rate-limiter.replenishRate: 1
# 令牌桶的上限
redis-rate-limiter.burstCapacity: 3
- RewritePath=/service-product/(?<segment>.*), /$\{segment}
#eureka注册中心
eureka:
client:
service-url:
defaultZone: http://localhost:9003/eureka/
instance:
prefer-ip-address: true #使用ip地址注册
在 application.yml 中添加了redis的信息,并配置了RequestRateLimiter的限流过滤器:
- burstCapacity,令牌桶总容量。
- replenishRate,令牌桶每秒填充平均速率。
- key-resolver,用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据# {@beanName}从 Spring 容器中获取 Bean 对象。
3.3 配置KeyResolver,基于请求路径的限流
为了达到不同的限流效果和规则,可以通过实现 KeyResolver 接口,定义不同请求类型的限流键。
@Configuration
public class KeyResolverConfiguration {
/**
* 基于请求路径的限流
*/
@Bean
public KeyResolver pathKeyResolver() {
return new KeyResolver() {
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getPath().toString());
}
};
}
}
3.4 测试
这个时候,依赖,配置文件,网关filter 都准备好了,重启gateway 模块,疯狂点击通过网关服务请求的接口,如:http://localhost:8080/service-product/product/1,会出现
及为生效。
3.5 基于参数的限流
3.5.1 在限流的配置文件里添加如下代码
/**
*
* 基于用户的限流
* */
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getQueryParams().getFirst("user")
);
}
package com.zjk.gateway.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Configuration
public class KeyResolverConfiguration {
/**
* 基于请求路径的限流
*/
@Bean
public KeyResolver pathKeyResolver() {
return new KeyResolver() {
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getPath().toString());
}
};
}
/**
*
* 基于用户的限流
* */
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getQueryParams().getFirst("user")
);
}
}
3.5.2 修改gateway 模块配置文件
修改成和上面定义的bean 同样的对象
并且把pathKeyResolver 注释掉