1.sentinel部署
下载地址:https://github.com/alibaba/Sentinel/releases 我们使⽤v1.7.1
启动:java -jar sentinel-dashboard-1.7.1.jar &
⽤户名/密码:sentinel/sentinel
2.服务改造
-
pom.xml引入依赖
<!--sentinel 核⼼环境 依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
-
application.yml修改
server: port: 8099 spring: application: name: lagou-service-autodeliver cloud: nacos: discovery: server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850 sentinel: transport: dashboard: 127.0.0.1:8088 #默认端口为8080,可以手动调整端口 port: 8719 # 该端口启动sentinel http server,用于接收控制台定义的限流规则,如果8719端口被占用,那么会依次+1 management: endpoints: web: exposure: include: "*" endpoint: health: show-details: always # 配合Logger.Level 打印fei调用日志 logging: level: com.lagou.edu.feign.ResumeServiceFeignClient: debug org.springframework.web.servlet.DispatcherServlet: debug lagou-service-resume: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #负载策略调整 #请求超时时间 #ConnectTimeOut: 2000 #请求处理超时时间 #ReadTimeOut: 5000 #对所有操作都进行充实 OkToRetryOnAllOperations: true ##根据如上配置,当访问到故障请求的时候,它会再尝试访问一次当前实例(次数由MaxAutoRetries配置) , ####如果不行,就换-一个实例进行访问,如果还不行,再换一次实例访问(更 换次数由MaxAutoRetriesNextServer配置) ##如果依然不行,返回失败信息。 MaxAutoRetries: 0 #对当前选中实例重试次数,不包括第一次调用 MaxAutoRetriesNextServer: 0 #切换实例的重试次数
3.Sentinel流控规则
-
资源名:默认为请求路径
-
针对来源:通过填入微服务名称指定调用者进行限流,默认default(不区分来源)
-
阈值类型+单机阈值:
- QPS:每秒钟调用该资源的请求数。
- 线程数:控制调用该资源的线程数量。(如果线程请求处理业务逻辑执行时间过长,当流量洪峰来临时,会开启大量线程资源,导致线程资源迅速打满,最终造成服务不可用,进而导致上有服务不可用,最终可能引起服务雪崩)
-
是否集群:集群限流
-
流控模式
-
直接:达到阈值条件时,直接限流
-
关联:关联的资源达到阈值条件时,对定义资源名进行限流
-
链路:指定入口进来的请求达到阈值才回进行限流
-
- 流控效果
- 快速失败
- Warm Up(预热)
- 排队等待
4.Sentinel降级规则
4.1RT(Response Time) 响应时间
Sentinel默认统计的RT上限是4900ms,超出次阈值的都算错4900ms。
可以在java -jar 启动追加命令配置RT上限时间。
java -jar sentinel-xxx.jar -Dcsp.sentinel.statistic.max.rt=5000
4.2异常比例
资源每秒请求超过5次,并且异常比例超过总数百分比后,资源进入降级
异常比例范围:[0 - 1] ,代表 [0% - 100%]
4.3异常数
统计1分钟内异常数目超过阈值后,会进行降级处理,由于异常数统计是按分钟计算的,时间窗口若小于60s,则结束熔断状态后仍可能再次进入熔断状态。建议时间窗口设置≥60s。
5.Sentinel自定义兜底逻辑
@SentinelResource注解类似Hystrix中的@HystrixCommand注解
@SentinelResource属性
- blockHandler:用来指定不满足Sentinel规则的降级兜底方法
- fallBack:用来指定Java运行时异常的兜底方法
5.1API接口资源配置
/**
* @SentinelResource value:定义资源名
* blockHandlerClass:指定Sentinel规则异常兜底逻辑所在class类
* blockHandler:指定Sentinel规则异常兜底逻辑具体哪个⽅法
* fallbackClass:指定Java运⾏时异常兜底逻辑所在class类
* fallback:指定Java运⾏时异常兜底逻辑具体哪个⽅法
*/
@GetMapping("/checkState/{userId}")
@SentinelResource(value = "findResumeOpenState", blockHandlerClass = SentinelFallbackClass.class, blockHandler = "handleException",
fallback = "handleError", fallbackClass = SentinelFallbackClass.class)
public Integer findResumeOpenState(@PathVariable Long userId) {
Integer defaultResumeState = resumeServiceFeignClient.findDefaultResumeState(userId);
return defaultResumeState;
}
5.2自定义兜底逻辑类
兜底类中的方法为static静态方法
public class SentinelFallbackClass {
public static Integer handleException(@PathVariable Long userId, BlockException blockException) {
return -100;
}
public static Integer handleError(@PathVariable Long userId) {
return -200;
}
}
5.3统一异常处理方法
@Component //Spring IOC实例化并管理该对象
public class UrlBlockHandler implements BlockExceptionHandler {
/**
* RESTFul异常信息处理器
* @param httpServletRequest
* @param httpServletResponse
* @param e
* @throws Exception
*/
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
String msg = null;
if(e instanceof FlowException){//限流异常
msg = "接口已被限流";
}else if(e instanceof DegradeException){//熔断异常
msg = "接口已被熔断,请稍后再试";
}else if(e instanceof ParamFlowException){ //热点参数限流
msg = "热点参数限流";
}else if(e instanceof SystemBlockException){ //系统规则异常
msg = "系统规则(负载/....不满足要求)";
}else if(e instanceof AuthorityException){ //授权规则异常
msg = "授权规则不通过";
}
httpServletResponse.setStatus(500);
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("application/json;charset=utf-8");
//ObjectMapper是内置Jackson的序列化工具类,这用于将对象转为JSON字符串
ObjectMapper mapper = new ObjectMapper();
//某个对象属性为null时不进行序列化输出
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.writeValue(httpServletResponse.getWriter(),
new ResponseObject(e.getClass().getSimpleName(), msg)
);
}
}
6.基于Nacos持久化Sentinel规则
6.1 添加maven依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
6.2添加application.yml配置
spring:
application:
name: lagou-service-autodeliver
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850
sentinel:
transport:
dashboard: 127.0.0.1:8088
port: 8719
# Sentinel Nacos数据源配置
datasource:
# 自定义的流控规则名称 flow
flow:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
data-id: ${spring.application.name}-flow-rules
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow # 流控规则
# 自定义的降级规则名称 degrade 06
degrade:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
data-id: ${spring.application.name}-degrade-rules
groupId: DEFAULT_GROUP
data-type: json
rule-type: degrade # 流控规则
6.3Nacos Server添加规则配置
6.3.1 流控规则配置
[
{
"resource": "findResumeOpenState",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
更详细的属性参考FlowRule类源码
- resource:资源名称
- limitApp:受来源限制的应用程序名称。 默认是default ,这意味着允许所有原始应用程序。
- grade:流量控制的阈值类型(0:线程数,1:QPS)。
- count:流量控制阈值计数。
- strategy:基于调用链的流控策略。0.用于直接流量控制; 1.用于相关流量控制(具有相关资源); 2.用于链流控制(按入口资源)。
- refResource:使用相关资源或上下文在流控制中引用资源。
- controlBehavior:速率限制器控制行为。 0.默认(直接拒绝),1.预热,2.限速器,3.预热+限速器
- warmUpPeriodSec:预热时长
- maxQueueingTimeMs:最大队列等待时间
- clusterMode:是否集群
- clusterConfig:集群模式的流控规则配置(ClusterFlowConfig.class)
- controller:流量控制器(TrafficShapingController.class)
6.3.2 降级规则配置
[
{
"resource": "findResumeOpenState",
"grade": 2,
"count": 1,
"timeWindow": 5
}
]
更详细的属性参考DegradeRule类源码
- resource:资源名称。
- grade:降级策略(0:平均 RT,1:异常率)。
- count:RT 阈值或异常比率阈值计数
- limitApp:受来源限制的应用程序名称。 默认是default ,这意味着允许所有原始应用程序。
- timeWindow:发生降级时降级恢复超时(以秒为单位)。