第一章 Java线程池技术应用
第二章 CountDownLatch和Semaphone的应用
第三章 Spring Cloud 简介
第四章 Spring Cloud Netflix 之 Eureka
第五章 Spring Cloud Netflix 之 Ribbon
第六章 Spring Cloud 之 OpenFeign
第七章 Spring Cloud 之 GateWay
第八章 Spring Cloud Netflix 之 Hystrix
第九章 代码管理gitlab 使用
第十章 SpringCloud Alibaba 之 Nacos discovery
第十一章 SpringCloud Alibaba 之 Nacos Config
第十二章 Spring Cloud Alibaba 之 Sentinel
Sentinel 是由阿里巴巴中间件团队开发的开源项目,是一种面向分布式微服务架构的轻量级高可用流量控制组件。
Sentinel 主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度帮助用户保护服务的稳定性。
Sentinel 主要由以下两个部分组成:
Sentinel 的基本概念有两个,它们分别是:资源和规则。
基本概念 | 描述 |
---|---|
资源 | 资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如由应用程序提供的服务或者是服务里的方法,甚至可以是一段代码。 我们可以通过 Sentinel 提供的 API 来定义一个资源,使其能够被 Sentinel 保护起来。通常情况下,我们可以使用方法名、URL 甚至是服务名来作为资源名来描述某个资源。 |
规则 | 围绕资源而设定的规则。Sentinel 支持流量控制、熔断降级、系统保护、来源访问控制和热点参数等多种规则,所有这些规则都可以动态实时调整。 |
下载:https://github.com/alibaba/Sentinel/releases
放到D:盘的sentinel目录里面,并将其启动
java -jar sentinel-dashboard-1.8.5.jar
启动后,访问地址:http://localhost:8080/
用户名和密码:sentinel/sentinel
引进sentinel依赖 -> 定义资源 -> 定义规则 -> 校验规则
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
<version>2021.0.4.0version>
dependency>
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
<version>1.8.5version>
dependency>
sentinel:
transport:
#配置 Sentinel dashboard 地址
dashboard: localhost:8080
#默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
port: 8719
@SentinelResource(value=“user-userInfoList”)
@SentinelResource(value = "tiger-test",blockHandler = "userInfoListBlockHandler")
public List<UserInfo> userInfoList(){
return this.userService.userInfoList();
}
public List<UserInfo> userInfoListBlockHandler(BlockException blockException){
log.info("#########################################userInfoListBlockHandler");
return null;
}
属性 | 说明 | 默认值 |
---|---|---|
资源名 | 流控规则的作用对象。 | - |
阈值 | 流控的阈值。 | - |
阈值类型 | 流控阈值的类型,包括 QPS 或并发线程数。 | QPS |
针对来源 | 流控针对的调用来源。 | default,表示不区分调用来源 |
流控模式 | 调用关系限流策略,包括直接、链路和关联。 | 直接 |
流控效果 | 流控效果(直接拒绝、Warm Up、匀速排队),不支持按调用关系限流。 | 直接拒绝 |
使用场景:
a、两个有竞争关系的资源
b、一个优先级较高,一个优先级较低
spring:
cloud:
sentinel:
web-context-unify: false # 关闭context整合
快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。
warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值。
排队等待:让所有的请求按照先后次序排队执行,两个请求的间隔不能小于指定时长
当请求超过QPS阈值时,快速失败和warm up
会拒绝新的请求并抛出异常。而排队等待则是让所有请求进入一个队列中,然后按照阈值允许的时间间隔依次执行。后来的请求必须等待前面执行完成,如果请求预期的等待时间超出最大时长,则会被拒绝。
例如:QPS = 5,意味着每200ms处理一个队列中的请求;timeout =
2000,意味着预期等待超过2000ms的请求会被拒绝并抛出异常
打开命令行窗口,执行以下命令查看资源的实时统计信息。
curl http://localhost:8719/cnode?id=userInfolist
idx id thread pass blocked success total aRt 1m-pass 1m-block 1m-all exceptio
2 userInfoList 0 0.0 0.0 0.0 0.0 0.0 10 16 26 0.0
实时统计信息各列名说明如下:
Sentinel 的熔断将机制会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),暂时切断对这个资源的调用,以避免局部不稳定因素导致整个系统的雪崩。
Sentinel 提供了 3 种熔断策略
状态 | 说明 | 触发条件 |
---|---|---|
熔断关闭状态(CLOSED) | 处于关闭状态时,请求可以正常调用资源。 | 满足以下任意条件,Sentinel 熔断器进入熔断关闭状态:
|
熔断开启状态 (OPEN) | 处于熔断开启状态时,熔断器会一定的时间(规定的熔断时长)内,暂时切断所有请求对该资源的调用,并调用相应的降级逻辑使请求快速失败避免系统崩溃。 | 满足以下任意条件,Sentinel 熔断器进入熔断开启状态:
|
探测恢复状态(HALF-OPEN) | 处于探测恢复状态时,Sentinel 熔断器会允许一个请求调用资源。则若接下来的一个请求成功完成(没有错误)则结束熔断,熔断器进入熔断关闭(CLOSED)状态;否则会再次被熔断,熔断器进入熔断开启(OPEN)状态。 | 在熔断开启一段时间(降级窗口时间或熔断时长,单位为 s)后,Sentinel 熔断器自动会进入探测恢复状态。 |
Sentinel 熔断规则属性
属性 | 说明 | 默认值 | 使用范围 |
---|---|---|---|
资源名 | 规则的作用对象。 | - | 所有熔断策略 |
熔断策略 | Sentinel 支持3 中熔断策略:慢调用比例、异常比例、异常数策略。 | 慢调用比例 | 所有熔断策略 |
最大 RT | 请求的最大相应时间,请求的响应时间大于该值则统计为慢调用。 | - | 慢调用比例 |
熔断时长 | 熔断开启状态持续的时间,超过该时间熔断器会切换为探测恢复状态(HALF-OPEN),单位为 s。 | - | 所有熔断策略 |
最小请求数 | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入)。 | 5 | 所有熔断策略 |
统计时长 | 熔断触发需要统计的时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入)。 | 1000 ms | 所有熔断策略 |
比例阈值 | 分为慢调用比例阈值和异常比例阈值,即慢调用或异常调用占所有请求的百分比,取值范围 [0.0,1.0]。 | - | 慢调用比例 、异常比例 |
异常数 | 请求或调用发生的异常的数量。 | - | 异常数 |
[
{
"resource": "tiger-test",
"limitApp": "default",
"grade": 1,
"count": 5,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
limitApp:来源应用;
[
{
"resource": "user-userInfoList",
"grade": 0,
"limitApp": "default",
"count":2000,
"slowRatioThreshold": 0.6,
"timeWindow": 60,
"minRequestAmount": 5,
"statIntervalMs":8000,
"clusterMode": false
}
]
工程配置读取nacos的限流规则(跟sentinel同级)
datasource:
ds:
nacos:
server-addr: localhost:8848
data-id: user-sentinel
group-id: DEFAULT_GROUP
rule-type: flow
/**
* 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),
datasource:
ds1:
nacos:
server-addr: localhost:8848
data-id: user-sentinel-flow
group-id: DEFAULT_GROUP
rule-type: flow
ds2:
nacos:
server-addr: localhost:8848
data-id: user-sentinel-degrade
group-id: DEFAULT_GROUP
rule-type: degrade
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-sentinel-gatewayartifactId>
<version>2021.0.4.0version>
dependency>
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
<version>1.8.5version>
dependency>
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-spring-cloud-gateway-adapterartifactId>
<version>1.8.6version>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
<version>2021.0.4.0version>
dependency>
sentinel:
transport:
# 配置Sentinel dashboard地址
dashboard: localhost:8080
# 默认8719端口,键入被占用会自动从8719+1,直到找到未被占用的端口
port: 8719
接下来对sentinel控制台中对gateway网关链路的流控配置项做详细的介绍,下图所示都是针对网关api附加的。
API类型
我们可以根据某个路由进行流控,也可以根据API分组进行流控,也就是请求访问地址来进行流控
首先创建API分组
选择API分组
然后在进行相应的流控规则。
针对请求属性
参数属性有五种:客户端ip、远程请求地址、请求头、请求url参数、Cookie
这里其实也就是对应的gateway中路由的匹配规则
匹配模式提供了三种:精确、子串、正则
子串匹配模式就是:我们指定127,它会自动再结尾加上%进行模糊匹配——127%
Client IP
测试
Remote Host
因为我们没有远程域名,所以这里就不进行测试了
Header
使用postman请求进行测试,如果请求头不为这个值就不会被限流
URL参数
测试
间隔
这个间隔的意思就是,以前1秒钟请求三次就会抛异常,而现在是两秒内请求三次才会抛异常,也就是说间隔从以前的一秒改变了。
Burst size
Burst size相当于是一个宽容次数,以前是1秒钟请求三次就会报异常,现在会宽容1次,也就是一秒钟请求大于三次才会抛异常
网关流控规则 GatewayFlowRule 的核心属性如下:
① resourceMode:规则是针对 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID)还是用户在 Sentinel 中定义的 API 分组(RESOURCE_MODE_CUSTOM_API_NAME),默认是 route。
② resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。
③ grade:限流指标维度,同限流规则的 grade 字段
④ count:限流阈值
⑤ intervalSec:统计时间窗口,单位是秒,默认是 1 秒
⑥ controlBehavior:流量整形的控制效果,目前支持快速失败和匀速排队两种模式,默认是快速失败。
⑦ burst:应对突发请求时额外允许的请求数目。
⑧ maxQueueingTimeoutMs:匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效。
⑨ paramItem:参数限流配置。若不提供,则代表不针对参数进行限流,该网关规则将会被转换成普通流控规则;否则会转换成热点规则。其中的字段:
parseStrategy:从请求中提取参数的策略,目前支持提取来源 IP(PARAM_PARSE_STRATEGY_CLIENT_IP)、Host(PARAM_PARSE_STRATEGY_HOST)、任意 Header(PARAM_PARSE_STRATEGY_HEADER)和任意 URL 参数(PARAM_PARSE_STRATEGY_URL_PARAM)四种模式。
fieldName:若提取策略选择 Header 模式或 URL 参数模式,则需要指定对应的 header 名称或 URL 参数名称。
pattern:参数值的匹配模式,只有匹配该模式的请求属性值会纳入统计和流控;若为空则统计该请求属性的所有值。
matchStrategy:参数值的匹配策略,目前支持精确匹配(PARAM_MATCH_STRATEGY_EXACT)、子串匹配(PARAM_MATCH_STRATEGY_CONTAINS)和正则匹配(PARAM_MATCH_STRATEGY_REGEX)。
降级规则
(resource、grade、count、slowRatioThreshold、timeWindow、minRequestAmount、statIntervalMs)
自定义异常返回结果:
sentinel:
scg:
fallback:
mode: response
response-status: 200
response-body: '{"code":"500","message": "系统忙,请稍候再试"}'
代码实现:
/**
* 熔断、降级回调
*/
@Configuration
public class SentinelGatewayConfig {
/**
* 这里可以写降级逻辑
*/
public SentinelGatewayConfig() {
GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
// 网关限制了请求,就会调用此回调 Mono Flux
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
ResponseDTO<Object> objectResponseDTO = new ResponseDTO<>();
objectResponseDTO.setCode(500);
objectResponseDTO.setMessage("系统异常,请稍候重试");
String errJson = JSON.toJSONString(objectResponseDTO);
Mono<ServerResponse> body = ServerResponse.ok().body(Mono.just(errJson), String.class);
return body;
}
});
}
}
将路由、限流、降级规则持久化到nacos配置中心
spring:
application:
name: drp-gateway-service
profiles:
#开发环境dev,测试环境test,生产环境prod
active: dev
jackson:
time-zone: GMT+8
cloud:
loadbalancer:
ribbon:
enabled: false
nacos:
discovery:
server-addr: localhost:8848 #Nacos server 的地址
#路由配置
config:
server-addr: localhost:8848
name: gateway-router
namespace: public
group: DEFAULT_GROUP
#file-extension: json #指定yaml格式的配置
refresh-enabled: true #支持刷新
#限流熔断配置
sentinel:
transport:
# 配置Sentinel dashboard地址
dashboard: localhost:8080
# 默认8719端口,键入被占用会自动从8719+1,直到找到未被占用的端口
port: 8719
datasource:
ds:
nacos:
server-addr: localhost:8848
data-id: user-sentinel
group-id: DEFAULT_GROUP
rule-type: flow