springCloud配置
网关:zuul
注册中心:eureka
4种限流策略(type)
1、User:通过对已认证的用户进行限流
2、Origin:针对请求的Origin限流,ip限流
3、url:对于url进行限流
4、不配置type即默认根据servceId进行限流,即根据服务进行限流
临时变量储存方式(repository)
1、IN_MEMORY:默认存储方式,基于ConcrrentHashMap
2、REDIS:基于redis存储,zuul多节点部署的时候建议用
3、JPA:spring data JPA 基于数据库存储
4、CONSUL:consul 的kv存储
5、BUKET4J:一个Java编写的基于令牌桶算法的限流库
ratelimit参数配置事例:
zuul:
ratelimit:
key-prefix: your-prefix #对应用来标识请求的key的前缀,自行设置
enabled: true #是否开启限流
repository: REDIS #对应存储类型(用来存储统计信息)
behind-proxy: true #代理之后
default-policy: #可选 - 针对所有的路由配置的策略,除非特别配置了policies
limit: 10 #可选 - 每个刷新时间窗口对应的请求数量限制
quota: 1000 #可选- 每个刷新时间窗口对应的请求时间限制(秒)
refresh-interval: 60 # 刷新时间窗口的时间,默认值 (秒)
type: #可选 限流方式,不选则默认serviceId根据服务进行限流
- user
- origin
- url
policies:
myServiceId: #特定的路由
limit: 10 #可选- 每个刷新时间窗口对应的请求数量限制
quota: 1000 #可选- 每个刷新时间窗口对应的请求时间限制(秒)
refresh-interval: 60 # 刷新时间窗口的时间,默认值 (秒)
type: #可选 限流方式
- user
- origin
- url
maven配置
spring-cloud-zuul-ratelimit根据不同的maven版本相关配置可能有变化
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.marcosbarbero.cloud</groupId>
<artifactId>spring-cloud-zuul-ratelimit</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>
</dependencies>
通过入参自定义key策略
如果希望自定义key,那么可以使用自定义RateLimitKeyGenerator来实现增加自己的策略逻辑
例如:根据不通的name进行判定每个name在一分钟内只允许通过10次
配置rateLimit:
ratelimit:
key-prefix: springcloud-book #按粒度拆分的临时变量key前缀
enabled: true #启用开关
repository: IN_MEMORY #key存储类型,默认是IN_MEMORY本地内存,此外还有多种形式
behind-proxy: true #表示代理之后
default-policy: #全局限流策略,可单独细化到服务粒度
limit: 10 #在一个单位时间窗口的请求数量
quota: 1000 #在一个单位时间窗口的请求时间限制
refresh-interval: 60 #单位时间窗口
type:
- user #可指定用户粒度
- origin #可指定客户端地址粒度
- url #可指定url粒度
自定义key实现RateLimitKeyGenerator:
@RequiredArgsConstructor
public class CustomRateLimitKeyGenerator implements RateLimitKeyGenerator {
private final RateLimitProperties properties;
private final RateLimitUtils rateLimitUtils;
@Override
public String key(final HttpServletRequest request, final Route route, final Policy policy) {
//policy限流配置中的类型可配置多个,集合方式获取
final List<Type> types = policy.getType().stream().map(MatchType::getType).collect(Collectors.toList());
//拼接字符串以冒号分隔
final StringJoiner joiner = new StringJoiner(":");
//获取请求中的参数name
String name=request.getParameter("name");
//获取配置文件临时变量key前缀properties.getKeyPrefix()
joiner.add(properties.getKeyPrefix());
joiner.add(name);
/**if (route != null) {
joiner.add(route.getId());
}
if (!types.isEmpty()) {
if (types.contains(Type.URL) && route != null) {
joiner.add(route.getPath());
}
if (types.contains(Type.ORIGIN)) {
joiner.add(rateLimitUtils.getRemoteAddress(request));
}
if (types.contains(Type.USER)) {
joiner.add(rateLimitUtils.getUser(request));
}**/
}
//转换成字符串形成key返回
return joiner.toString();
}
}
限流原理(redis、JPA、Consul)
redis、jpa、concul这三种是通过计数器进行限流,不同的限流策略生成一个key,计算剩余限流相关数据是存入rate中,key-rate一一对应。请求进入后,根据key查找有没有相关rate生成,没有则生成rate保存,后置filter进行更行剩余请求次数,请求耗时。
前置过滤:获取route数据,策略集合,遍历集合,生成限流key,创建rate对象,比较limit请求次数,请求时间是否超出阈值。
后置过滤:计算请求耗时,更新rate对象中的剩余请求次数,请求时间阈值
源码中rate实体类:
public class Rate {
@Id
@Column(name = "rate_key")
private String key;
/**
* 剩余的请求数
*
*/
private Long remaining;
/**
* 剩余的请求耗时
*
*/
private Long remainingQuota;
/**
*
*
*/
private Long reset;
/**
* 过期时间
*
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy HH:mm:ss")
private Date expiration;
}