网关流控定义
Sentinel支持对Spring Cloud Gateway、Zuul等主流的API Gataway 进行限流,作用在网关的流控称之为网关流控
,其实现原理请点击网关限流进入官方Wiki查看。
这里只把原理图从官方文档摘出来,需多关注图中提到的模块名和几个类名,因为都是核心级别的存在。
规则类型gw-flow
和gw-api-group
为网关流控规则,具体类型请查看规则类型枚举RuleType
/**
* flow 流控规则
*/
FLOW("flow", FlowRule.class),
/**
* degrade 降级规则
*/
DEGRADE("degrade", DegradeRule.class),
/**
* param flow 热点规则
*/
PARAM_FLOW("param-flow", ParamFlowRule.class),
/**
* system 系统规则
*/
SYSTEM("system", SystemRule.class),
/**
* authority 授权规则
*/
AUTHORITY("authority", AuthorityRule.class),
/**
* gateway flow 网关限流规则
*/
GW_FLOW("gw-flow","com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),
/**
* api 用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合
*/
GW_API_GROUP("gw-api-group","com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");
网关流控规则
Field 说明 默认值 resource 资源名称,网关route或自定义API分组名称(注:网关route这里的值不是route.id,可调试 resourceMode 限流资源类型,网关route【0】或自定义API分组【1】(详细查看GatewayFlowRule
和SentinelGatewayConstants
)
网关route
grade
限流阈值类型,QPS【1】或线程数【0】
QPS
count
限流阈值,QPS阈值或线程数值
intervalSec
统计时间间隔,单位秒
1秒
controlBehavior
流控效果,目前支持快速失败【0】和匀速排队【1】
快速失败
burst
应对突发请求时额外允许的请求数目
maxQueueingTimeoutMs
匀速排队模式下的最长排队时间,单位毫秒,仅在匀速排队模式下生效
paramItem
参数属性配置,parseStrategy:提取参数策略(0:Clien IP,1:Remote HOST,2:Header,3:请求参数,4:Cookie);fieldName:若提取策略是Header模式或者URL参数模式,则需要指定header名称或URL参数名称;pattern:参数值的匹配模式;matchStrategy:参数值的匹配策略,支持精确匹配,子串匹配和正则匹配。
网关流控客户端标识
网关流控和普通流控有很多区别,其中网关流控类型是gw-flow
,普通流控类型是flow
怎么标识流控是网关类型呢?
很多博客文章都没有着重此点,因为前阵子纠结于网关流控的面板和普通流控的面板不一致而去搜相关的资料,最后还是在Sentinel官方文档中找到此开关,就是需要在gateway-sentinel
网关应用添加JVM启动参数。
# 注:通过 Spring Cloud Alibaba Sentinel 自动接入的 API Gateway 整合则无需此参数
-Dcsp.sentinel.app.type=1
具体如下图:
或者在启动类中main
方法中添加如下代码:
// 添加此代码,在Sentinel控制台中做判断使用
System.setProperty("csp.sentinel.app.type", "1");
集成
- 新建
gateway-sentinel
模块,并导入如下依赖
<!--nacos注册中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--spring cloud gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--spring cloud gateway整合sentinel的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<!--sentinel的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- Sentinel规则持久化至Nacos配置 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.7</version>
</dependency>
- 网关配置,在
application.yml
添加nacos
和Sentinel
的配置,同时配置路由转发
server:
port: 10015
spring:
application:
name: gateway-sentinel
cloud:
# 整合sentinel,配置sentinel控制台的地址
sentinel:
web-context-unify: false
datasource:
gw-api-group:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
username: ${spring.cloud.nacos.discovery.username}
password: ${spring.cloud.nacos.discovery.password}
namespace: ${spring.cloud.nacos.discovery.namespace}
group-id: SENTINEL_GROUP
data-id: ${spring.application.name}-gateway-api-rules
# 规则类型:flow、degrade、param-flow、system、authority、gw-flow、gw-api-group
rule-type: gw-api-group
gw-flow:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
username: ${spring.cloud.nacos.discovery.username}
password: ${spring.cloud.nacos.discovery.password}
namespace: ${spring.cloud.nacos.discovery.namespace}
group-id: SENTINEL_GROUP
data-id: ${spring.application.name}-gateway-flow-rules
# 规则类型:flow、degrade、param-flow、system、authority、gw-flow
rule-type: gw-flow
# 熔断降级
degrade:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
username: ${spring.cloud.nacos.discovery.username}
password: ${spring.cloud.nacos.discovery.password}
namespace: ${spring.cloud.nacos.discovery.namespace}
group-id: SENTINEL_GROUP
data-id: ${spring.application.name}-degrade-rules
rule-type: degrade
# 系统规则
system:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
username: ${spring.cloud.nacos.discovery.username}
password: ${spring.cloud.nacos.discovery.password}
namespace: ${spring.cloud.nacos.discovery.namespace}
group-id: SENTINEL_GROUP
data-id: ${spring.application.name}-system-rules
rule-type: system
transport:
## 指定控制台的地址,默认端口8080
dashboard: 192.168.0.102:6005
client-ip: 192.168.0.104
port: 8719
eager: true
nacos:
# 注册中心配置
discovery:
# nacos的服务地址,nacos-server中IP地址:端口号
server-addr: 192.168.0.102:8848
username: nacos
password: nacos
namespace:
gateway:
# 路由
routes:
# id只要唯一即可,名称任意
- id: nacos-sentinel
uri: http://localhost:9004
## 配置断言
predicates:
- Path=/sentinel/**
management:
endpoints:
web:
exposure:
## yml文件中存在特殊字符,必须用单引号包含,否则启动报错
include: '*'
这里解释下配置中的datasource,因为在Sentinel添加流控规则之后,如果重启服务,之前配置的规则就会消失,所>以这里需要持久化Sentinel配置,从上面的配置可以看出选择的是Nacos。
网关流控测试
-
启动
gateway-sentinel
模块 -
启动
nacos-sentinel
模块 -
打开
sentinel
控制台,给nacos-sentinel
api添加流控规则,设置阈值为5,即1秒最多发5次请求 -
打开
jmeter
,添加Thread Group
,设置1秒10次请求 -
添加HTTP请求
-
添加察看结果树,因为要看请求的响应,所以这里添加察看结果树
-
启动线程组,每秒15次认证请求
需要注意的是,如果测试计划有多个线程组,需禁用除了测试之外的其他线程组。
-
点击
查看结果树
查看请求的情况 -
进入Sentinel控制台,查看实时监控
自定义网关流控异常
上面Sentinel限流的默认异常响应如下
{"code":429,"message":"Blocked by Sentinel: ParamFlowException"}
假如想自定义网关流控异常响应,该如何实现呢?
可以通过在GatewayCallbackManager上通过setBlockHandler方法注册回调实现,当请求被限流后,实现自定义的异常响应。
自定义异常代码:
package com.example.config;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.example.enums.CodeEnum;
import com.example.utils.ResponseResult;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import javax.annotation.PostConstruct;
@Configuration
public class SentinelConfig {
@PostConstruct
private void initBlockHandler() {
BlockRequestHandler blockRequestHandler = (exchange, t) ->
ServerResponse.status(CodeEnum.FLOW_LIMIT.getCode())
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(ResponseResult.builder().error(CodeEnum.FLOW_LIMIT).build()));
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
}
JMeter中查看被限流的响应,可以看到已按照自定义的响应异常返回
Java开发手册上的关于
系统限流
的错误码默认为B0210