SpringCloud微服务安全网关安全 3-8 用开源项目spring-cloud-zuul-ratelimit 做网关上的限流
Posted 鮀城小帅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud微服务安全网关安全 3-8 用开源项目spring-cloud-zuul-ratelimit 做网关上的限流相关的知识,希望对你有一定的参考价值。
1. 网关的限流
用开源项目spring-cloud-zuul-ratelimit 做网关上的限流 (项目github:https://github.com/marcosbarbero/ )
1.1 引入限流组件依赖
在 this-security-gateway网关项目中引入限流组件的maven依赖
<dependency>
<groupId>com.marcosbarbero.cloud</groupId>
<artifactId>spring-cloud-zuul-ratelimit</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
1.2 在网关项目yml配置里,配置限流相关配置
限流的信息,在redis是有有效期的,过了有效期会自动清除,所以要想在redis看到限流的相关信息,这里时间窗口就设置为 10 秒(刚开始我设置的是1秒,redis死活看不到限流信息,浪费了十几分钟时间)
zuul:
routes: # 路由的配置是个map,可以配置多个
token: #token结尾的请求,都转发到http://localhost:9090认证服务器地址
url: http://localhost:9090
order: #order结尾的请求,都转发到http://localhost:9070 订单服务
url: http://localhost:9080
sensitive-headers: #设置敏感头设置为空,Authorization等请求头的请求,都往后转发
ratelimit:
enabled: true
repository: REDIS
default-policy-list:
# ########### 如下的配置就是说:每1秒内不能超过2个请求,2个请求时间加起来不能超过1秒(quota)############
- limit: 2 #optional - request number limit per refresh interval window
quota: 1 #optional - request time limit per refresh interval window (in seconds)
refresh-interval: 60 #时间窗口 (in seconds)
type: ##根据什么控制流量,可以组合使用,如url、httpmethod组合,就会把 /orders的get和post请求分开处理
- url
- httpmethod
因为zuul使用ratelimit限流时用 JPA 存储导致抛出 JPARepository 没有将Bean实例化存储到容器中的问题,这里选择使用Redis来存储相关数据。
1.3 测试网关限流1
从网关获取一个token后,拿token访问网关创建订单。手速点的快点,Http就会返回 429 状态码,表示过多的请求。
看redis,已经有限流的信息了:
生成的限流的key是: rate:order:/orders:POST rate是配置的限流信息的前缀,order是zuul转发的规则,/orders:POST 是配置的限流类型 url 和http_method的组合
当下一个请求过来的时候就会计算key,然后根据key去redis找,看当前的key已经过了多少个请求了,来判断这次请求能不能过。
大部分情况下,根据user 、origin、 url 、http_method已经满足需求了。有些特殊的场景,需要根据传过来的参数进行限流,比如有两种优惠券A、B,优惠券A业务简单,每秒能处理100个请求,优惠券B复杂,每秒能处理10个请求,此时自带的限流规则就不能满足需求了。限流归根揭底是根据key来限流的,所以此时就要自定义key的生成规则。
自定义key的生成规则:
/**
* @ClassName MyKeyGen
* @Description TODO 自定义限流key生成规则,自定义限流规则
* @Author wushaopei
* @Date 2021/5/5 11:25
* @Version 1.0
*/
public class MyKeyGen extends DefaultRateLimitKeyGenerator {
@Override
public String key(HttpServletRequest request, Route route, RateLimitProperties.Policy policy) {
//可以从route拿出路由信息,自定义key生成规则:https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit#usage
return super.key(request, route, policy);
}
public MyKeyGen(RateLimitProperties properties, RateLimitUtils rateLimitUtils) {
super(properties, rateLimitUtils);
}
}
重写错误处理:
/**
* @ClassName MyRateLimitErrorHandler
* @Description TODO
* @Author wushaopei
* @Date 2021/5/5 11:29
* @Version 1.0
*/
@Component
public class MyRateLimitErrorHandler extends DefaultRateLimiterErrorHandler {
//限流数据存时候报错了的处理,一般不覆盖
@Override
public void handleSaveError(String key, Exception e) {
super.handleSaveError(key, e);
}
//限流取数据报错的处理,一般不覆盖
@Override
public void handleFetchError(String key, Exception e) {
super.handleFetchError(key, e);
}
//限流错误处理,记日志等
@Override
public void handleError(String msg, Exception e) {
super.handleError(msg, e);
}
}
2. 都在网关上做限流是有问题的
2.1 耦合
如上所述的根据不同的优惠券进行的限流,如果优惠券又多了种类型,就要重写网关的限流的代码,重写部署网关,这就是耦合,是不行的。服务和服务之间,以及服务和基础组件之间,一定要解耦。微服务场景下解耦是价值最大的事。一旦两个服务耦合在一块,一个变了,另一个也要跟着变。
2.2 限流的数量的问题
网关只能处理从整个微服务外边进来的请求,并不处理微服务之间的调用。如,有A B两个微服务,A还调用了B服务,A、B服务每秒处理的请求最大都是100个,网关限流 A 100请求/秒 ,B 100请求/秒。此时有100个A请求到网关,100个B请求也到了网关,都通过了网关,而此时,100个到A的请求又请求了100次B,导致B服务不可用!
所以:在网关上不要做细粒度的限流,没有用,因为很多服务之间的调用,都不走网关。网关层面只根据硬件设备的处理能力做一些限流,如服务的节点用的是tomcat,根据每个tomcat的资源配置,计算能处理的多少并发请求,根据这个去限流。具体的方法,跟业务逻辑的耦合,都不要发生在网关上的限流逻辑里。这就是上边配置里说的,限流类型 user最好不在网关上用。
以上是关于SpringCloud微服务安全网关安全 3-8 用开源项目spring-cloud-zuul-ratelimit 做网关上的限流的主要内容,如果未能解决你的问题,请参考以下文章
SpringCloud微服务安全网关安全 3-2 常见的微服务安全整体架构
重学SpringCloud系列八之微服务网关安全认证-JWT篇
SpringCloud微服务安全网关安全 3-3 搭建OAuth2 认证服务器