网关限流
Sentinel 支持对 Spring Cloud Gateway、Zuul 等主流的 API Gateway 进行限流。
Sentinel 1.6.0 引入了 Sentinel API Gateway Adapter Common 模块,此模块中包含网关限流的规则和自定义 API 的实体和管理逻辑:
- GatewayFlowRule:网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。
- ApiDefinition:用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以定义一个 API 叫 my_api,请求 path 模式为 /foo/** 和 /baz/** 的都归到 my_api 这个 API 分组下面。限流的时候可以针对这个自定义的 API 分组维度进行限流。
网关流控实现原理
当通过GatewayRuleManager 加载网关流控规则(GatewayFlowRule)时,无论是否针对请求属性进行限流,Sentinel 底层都会将网关流控规则转化为热点参数规则(ParamFlowRule),存储在 GatewayRuleManager 中,与正常的热点参数规则相隔离。转换时 Sentinel 会根据请求属性配置,为网关流控规则设置参数索引(idx),并同步到生成的热点参数规则中。
外部请求进入 API Gateway 时会经过 Sentinel 实现的 filter,其中会依次进行 路由/API 分组匹配、请求属性解析和参数组装。Sentinel 会根据配置的网关流控规则来解析请求属性,并依照参数索引顺序组装参数数组,最终传入 SphU.entry(res, args) 中。Sentinel API Gateway Adapter Common 模块向 Slot Chain 中添加了一个 GatewayFlowSlot,专门用来做网关规则的检查。GatewayFlowSlot 会从 GatewayRuleManager 中提取生成的热点参数规则,根据传入的参数依次进行规则检查。若某条规则不针对请求属性,则会在参数最后一个位置置入预设的常量,达到普通流控的效果。
整合Spring Cloud Gateway
从1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:
- route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId
- 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组
1. 搭建Gateway网关项目
这里不详细说明,可参照其他文档,框架版本:
- Nacos:1.4.1
- sentinel :1.8.0
- spring-cloud :Hoxton.RELEASE
- spring-cloud-alibaba:2.2.0.RELEASE
- spring.boot:2.2.13.RELEASE
2. gateway集成sentinel
首先添加cloud sentinel对gateway的相关依赖。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>
重点在Gateway的相关配置
- locator.enabled:gateway开启服务注册和发现的功能,这样就不需要自己配置各种route。
- scg.fallback:配置限流异常时响应的信息。
- route-id-prefix:配置routeId的前缀,采用了自动注册,最终routeId为 route-id-注册服务名
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1 nacos注册地址
config:
server-addr: 127.0.0.1 远程配置地址
sentinel:
transport:
dashboard: localhost:8080 sentinel注册地址
直接建立心跳
eager: true
scg:
限流后的响应配置
fallback:
content-type: application/json
模式 response、redirect
mode: response
响应状态码
response-status: 429
响应信息
response-body: 对不起,已经被限流了!!!
gateway:
spring cloud gateway 路由配置方式
discovery:
locator:
enabled: true 表明gateway开启服务注册和发现的功能
lower-case-service-id: true 将请求路径上的服务名配置为小写
route-id-prefix: route-id- 配置routeId的前缀,最终为 route-id-注册服务名
3. 启动控制台
启动控制台、注册中心、网关、应用后台(sentinel-client-demo),查看控制台,重点看下会有个API管理的菜单,如果没有
可参照这个文档Sentinel整合Gateway控制台不显示API管理。
对比普通应用的菜单,我们发现有几个不同点:
- 簇点链路=》请求链路
- 多了个API管理
- 没有热点规则
- 没有授权规则
- 没有集群流控
测试案例
1. 使用routId限流
点击流控规则菜单,添加规则,发现这里没有资源名称可以填写,只能选择 Route ID或者API分组。
我们添加一个 Route ID, Route ID就是Gateway路由里配置的ID,因为在Gateway中配置了route-id-prefix,所有这里应该写route-id-加上服务在Nacos注册的服务名。
以下配置表示对route-id-sentinel-client-demo这个路由进行访问时,QPS限制为一秒一次请求。
当我们快速访问Gateway配置的路由后端服务接口时,发现返回了我们配置的限流信息。
2. 使用API分组限流
在之前的案例中,一个访问接口,可以代表一个资源。
但是在网关中,Sentinel 网关流控默认的粒度是 route 维度以及自定义 API分组维度,默认不支持 URL 粒度。
这种可能是考虑到,网关作为所有后台应用的入口,如果不分组,那么肯定太多了。
比如我们根据限流规则建立一个分组,这个分组表示具体的限流策略。然后可以在这个分组下添加多个匹配模式,下面的规则表示,访问app1和访问app2后台应用时,可以在这个组添加一样的限流规则(这里需要添加通过网关访问时完整路径)。
注意精确是指完整匹配,前缀模式时需要添加**。
添加完分组后,我们在添加流控规则时,选择API分组,然后配置限流规则就可以了。。。
3.针对请求属性限流
在添加流控规则时,我们发现,还可以针对请求属性进行限流如 (URL 参数,Client IP,Header 等)。
比如,我们对谷歌浏览器进行限流,当消息头中User-Agent为谷歌浏览器时,触发限流。
测试使用谷歌浏览器,触发限流,而换个浏览器时,则正常访问。
4. 请求链路
在通过网关访问时,会自动生成当前访问的路由节点信息,我们也可以直接在这里添加规则。