Sentinel
类似于之前的Hystrix
,它的优点是有自己的监控平台,可以用Web界面来更加细粒度化的配置。
使用Sentinel
Sentinel
和Nacos
一样需要在Release
那里去下载,下载完成后直接使用java -jar
来运行就好了,默认的端口是8080
,运行后默认的登录账号和密码都是sentinel
。
然后在项目中导入下面坐标:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
配置:
server:
port: 8001
spring:
application:
name: sentinel-service
cloud:
sentinel:
transport:
dashboard: localhost:8080
# 默认使用8719端口,如果被占用则会自动+1扫描
port: 8719
management:
endpoints:
web:
exposure:
include: "*"
启动类略,写两个接口准备测试:
@RestController
public class EchoController {
@Value("${server.port}")
private String port;
@GetMapping(value = "/limitA")
public String limitA() {
return port + ": Hello Sentinel! A";
}
@GetMapping(value = "/limitB")
public String limitB() {
return port + ": Hello Sentinel! B";
}
}
访问上面的两个接口,即可在Sentinel控制面板中显示出来当前微服务的信息。
流量控制
QPS-直接-快速失败
疯狂点击接口limitA
,发现页面上会出现:Blocked by Sentinel (flow limiting)
,这就意味着一秒钟只能接收1次请求已经生效了。
线程数-直接
接口A修改为下面的样子。
@GetMapping(value = "/limitA")
public String limitA() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return port + ": Hello Sentinel! A";
}
修改流控规则到线程数-直接,阈值为1,然后进行测试。
然后疯狂的访问接口,这个时候也会显示Blocked by Sentinel (flow limiting)
,它和QPS的区别:
QPS限制的是请求的数量,请求超过数量就不允许请求进入了。
线程数是所有的请求都可以进入,只有当规定阈值个线程已经处理不过来了,才会出现流控提示。
流控模式-关联
举个具体使用的例子,比如说支付接口出现了问题,那么就去限流下订单的接口。也就是说支付接口和下订单接口是关联关系。
疯狂的访问/limitB
接口,然后发现/limitA
接口不能用了。
流控效果-Warm Up(预热)
预热是防止接口被突如其来的大量访问,某个接口一直处于无人问津的状态,突然间就有了特别大的访问量,所以需要提供预热的效果。
阈值为10,预热时长为5,系统的coldFactor
默认为3,意思就是还没有到预热时长的时候针对突如其来的访问只能让3个请求访问成功(10 / 3
),过了预热时长后就会到达正常的阈值。
流控效果-排队等待
设置QPS为1,然后在QPS达到规定的阈值之后会让后面的请求排队等待,除非后面的请求等的不耐烦了(超过了超时时间),页面上就会显示限流提示信息。
测试的时候可以通过打日志的方式:
log.info(Thread.currentThread().getName() + ": 进入了...");
2020-03-22 16:30:25.492 INFO 19344 --- [nio-8001-exec-2] com.cy.controller.EchoController : http-nio-8001-exec-2: 进入了...
2020-03-22 16:30:51.791 INFO 19344 --- [nio-8001-exec-4] com.cy.controller.EchoController : http-nio-8001-exec-4: 进入了...
2020-03-22 16:30:52.791 INFO 19344 --- [nio-8001-exec-5] com.cy.controller.EchoController : http-nio-8001-exec-5: 进入了...
2020-03-22 16:30:53.791 INFO 19344 --- [nio-8001-exec-6] com.cy.controller.EchoController : http-nio-8001-exec-6: 进入了...
2020-03-22 16:30:54.791 INFO 19344 --- [nio-8001-exec-7] com.cy.controller.EchoController : http-nio-8001-exec-7: 进入了...
2020-03-22 16:30:55.791 INFO 19344 --- [nio-8001-exec-8] com.cy.controller.EchoController : http-nio-8001-exec-8: 进入了...
2020-03-22 16:30:56.792 INFO 19344 --- [nio-8001-exec-9] com.cy.controller.EchoController : http-nio-8001-exec-9: 进入了...
降级规则
Sentinel
里面是没有半开(Half Open
)状态的。
RT(平均响应时间)
当1秒之内有5次请求,且5次请求的平均响应时间超过了设定的RT值(上图是200毫秒),接口会被限流,等到到达规定的时间窗口1S
,就会恢复正常的调用。
默认的RT上限是:4900ms
,超过4900ms
也算作4900ms
。
异常比例
异常比例,就不截图了。
还是在1秒之内5次请求,如果这5次请求的异常比例超过了设定的值,将会在规定的时间窗口期内接口无法使用,接口会提示Blocked by Sentinel (flow limiting)
时间窗口的时间过了之后就会提示异常信息了,而不是Blocked by Sentinel (flow limiting)
这是因为Blocked by Sentinel (flow limiting)
这个提示只有在降级的时候才会被显示。
异常数
异常数是按照分钟统计的,1分钟之内的异常数量超过了设定的数量,就会进入降级。
热点规则
举个比较形象的例子,比如说在微博中某个明星出轨了,基本上微博就会炸掉,热点规则就可以避免这个问题。
他是通过请求的参数进行限流的,当某个参数使用了相同的值进行了大量的访问,会被限流。
@GetMapping(value = "/limitC")
@SentinelResource(value = "limitC", blockHandler = "fallback")
public String limitC(String key1, String key2) {
return port + ": Hello Sentinel! " + key1 + " ==> " + key2;
}
public String fallback(String key1, String key2, BlockException e) {
return key1 + " ==> " + key2 + "已经被限流了..." + e.getMessage();
}
上面代码中使用了@SentinelResource
注解,该注解中的blockHandler
参数规定了降级方法。
这个配置的意思是,当第一个参数的单机阈值为1的时候进行降级,降级持续时长为1秒。
热点规则只能使用资源名(@SentinelResource
中的value
值)来进行限流,如果不使用blockHandler
,会抛出异常,所以热点规则要尽量添加blockHandler
。
添加参数例外项
也不需要解释太多的东西,一张图片就懂了。
当参数值为明星的时候,限流阈值为100。
需要注意blockHandler
只能作为与Sentinel
控制台配置不一致的时候使用的降级方法,不能作为程序异常时候的降级方法,应该添加fallback
参数,在降级方法中可以注入异常类
系统规则
相当于在整个系统上添加了规则,作用在全局的规则,更加粗粒度。
只支持5中模式:
降级方法解耦
写一个针对某个类的专门的降级类,里面的降级方法首先必须要是静态的,其次,必须要和它对应的降级方法的参数保持一致,并且加入BlockException
参数,否则将无法使用降级方法。
public class GlobalHandler {
public static String handler(String key1, String key2, BlockException e) {
return "全局的降级方法..." + e.getMessage();
}
}
@SentinelResource(value = "limitC",
blockHandlerClass = GlobalHandler.class,
blockHandler = "handler")
其他注意事项
如果按照资源名称(@SentinelResource
注解中的value
)进行限流,则会使用注解中的降级方法,如果按照URI
进行限流,则会使用系统默认的降级方法。
如果@SentinelResource
注解中加入了fallback
属性,则程序出现异常了就会走fallback
。
如果@SentinelResource
注解中加入了blockHandler
属性,则违反了Sentinel
规则后走handler
。
如果只配置fallback
,不配置blockHandler
则会默认使用Sentinel
的降级信息。
如果只配置blockHandler
,不配置fallback
并不会走程序异常时的降级方法。
可以使用exceptionsToIgnore
来规定某个异常不要被fallback
进行处理。
OpenFeign使用Sentinel
正常搭建起来一个OpenFeign
项目,在项目中加入Sentinel
的坐标,然后配置文件中添加:
feign:
sentinel:
enabled: true
和OpenFeign
使用Hystrix
的流程一样,需要对原来的OpenFeign
接口写一个实现类,然后在@FeignClient
注解中加入fallback
即可。
@FeignClient(value = "sentinel-service",
fallback = EchoServiceHandler.class)
...
Sentinel规则持久化
默认情况下Sentinel
会在微服务重启的时候,配置的规则就会消失,因为默认情况下规则是保存在微服务的内存中的。