在看Sentinel的降级限流之前,我们需要有一个全局的概念:
下载Sentinel的控制台:https://download.csdn.net/download/jiangxiulilinux/11961986
java -jar sentinel-dashboard-1.6.3.jar
默认的用户名,密码都是sentinel,登录后进入控制台,目前看是什么也没有的,接下来我们让服务接入咱们的限流组件。
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
在我们的application.yml的配置文件中,加入以下内容:
spring:
application:
name: sentinel-client
cloud:
sentinel:
transport:
port: 8719
dashboard: 127.0.0.1:8080
启动我们上面的应用,观察Sentinel的控制台,发现是如下的空的:
@RestController
@Slf4j
public class SentinelController {
@GetMapping("/getname")
public String getName(String name) {
log.info("sentinel client receive------------------{}", name);
return "Hello " + name + " !";
}
}
调用几次我们刚才的接口(http://127.0.0.1:8090/getname?name=jxl),应用有了访问量,再观察控制台,监控的效果出来了,应用也出来了。
这个概念很重要,我们所有的降级,限流还是系统规则,热点规则都要定义范围,这就是资源,我们将我们上文中定义的接口定义为sentinel的资源,名字为hello。
在我们的资源上面加入注解@SentinelResource
,就是定义了资源,可以参看如下的完整代码。
@RestController
@Slf4j
public class SentinelController {
@GetMapping("/getname")
@SentinelResource("hello")
public String getName(String name) {
log.info("sentinel client receive------------------{}", name);
return "Hello " + name + " !";
}
}
有了资源,一切都可以开始了。
我们看下流控如何配置的,可选类型有QPS与线程数,后面可以配置对应的阈值,我们暂定为QPS为2.
定义好流控的规则后,看我的流控规则里面有下面的显示:
接下来,就是见证奇迹的时候了,我们访问我们之前定义的接口,点击的快点后,发现了如下的返回:
大概意思就是,您没有定义错误页面,所以你看到了默认的错误页面,服务器发生了内部的错误。
看控制台的日志,已经报了FlowException的异常。
这样当然不是你想要的了,你想要有明确的返回,我们可以如下来做。
添加blockHandler的处理,它的值就是下面的方法的名字。
下面的方法,必须和资源的方法定义相同,同时多一个异常的参数。这个时候异常就不会暴露出到页面上了。我们可以自定义如何处理这个异常。
在控制台中,簇点路由->列表视图->降级。
一秒内
持续进入5个请求,对应时刻的平均响应时间超过阈值,那么在接下来的时间窗口中,将会发生降级,这里要注意,sentinel默认统计的RT的最高上限为4900ms,如果超过这个时间的时间都会按照4900来计算,我们可以通过启动配置项Dcsp.sentinel.statistic.max.rt=xxx
来配置。每秒
请求量超过5,且每秒的异常比例超过阈值,资源进入降级状态,在接下来的时间窗口内,对这个接口的调用都会自动返回。一分钟
的异常数目超过阈值后进行熔断。如果时间窗口小于60秒,则结束熔断状态后仍可能继续进入熔断状态。异常降级仅针对业务异常,对Sentinel降级限流本身的异常BlockException
不生效。
我们定义的降级规则如下,我们可以单独定义,最终是规则的合集,也就是本着安全的目的,任何一个规则达到了,都会生效。
如果我们什么也不做,只是在控制台中定义我们的降级规则,那么会一样的报错,报异常。
为了让我们的降级按照我们的想法返回,我们的程序如下:
@RestController
@Slf4j
public class SentinelController {
@GetMapping("/getname")
@SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "fallbackHandler")
public String getName(String name) {
long start = System.currentTimeMillis();
log.info("----------sentinel client receive {}----------", name);
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("----------react time {}----------", System.currentTimeMillis() - start);
throw new RuntimeException("出错啦");
//return "Hello " + name + " !";
}
public String exceptionHandler(String name, BlockException ex) {
String exception = "block";
if (ex instanceof FlowException){
log.info("----------flow ----------");
exception = "flow";
} else if(ex instanceof DegradeException){
log.info("----------degrade----------");
exception = "degrade";
}
return exception;
}
public String fallbackHandler(String name, Throwable ex) {
log.info("----------fallback----------");
return "fallback";
}
}
上面的代码中定义了降级后,我们的处理,也就是在资源上,添加fallback
的处理方法。
处理方法的要求是,需要返回值和参数与资源的方法相同,参数可以添加一个Throwable
的参数。
上面的代码中,模拟了异常发生的情况,用以测试异常的降级情况。
首先需要明确系统规则应用整体维度的,而不是资源维度的。
这几个维度的解释:
maxQps * minRt
计算得出,设定参考值一般是CPU cores * 2.5
。已经定义好了,会返回一串字符。
Blocked by Sentinel (flow limiting)
授权规则是对资源级别的控制,分为以下两种:
是针对资源中的参数的控制,使用LRU算法,针对某些参数的值的峰值进行控制。
举个例子吧,我们的接口中有个name参数,我们配置的规则是当这个参数的特定值超过2个访问量的时候,会返回block,但是我们下面设置了有例外情况,jxl这个值超过了阈值也允许,那么我们就可以做测试了。
当参数是jxl的时候,连续访问多次,也不会被限制。
但是换成其他的参数,连续访问次数超过了阈值,就会别限制,返回block。
花了好大的力气,终于把sentinel可以做的限制都总结完了。大家在验证的过程中一定遇到了很多的问题,这也是作者需要继续研究的问题。遗留问题如下:
持久化
。高可用
策略。集群
是如何降级与限流的。本文连载文章如下:
五分钟实现:Spring-Cloud-Alibaba-Nacos-服务治理
五分钟实现:Spring-Cloud-Alibaba-Nacos-配置中心
五分钟实现:Spring-Cloud-Alibaba-Sentinel-降级限流
五分钟实现:Spring-Cloud-Alibaba-Sentinel-限流持久化