启动后发现sentinel客户端空空如也,这是因为Sentinel采用的懒加载,这时候我们只需要调用下API即可。
超过一秒一次(或者设置线程数阙值,访问该api的线程数超过1秒一个),就会被限流,报错系统默认的错误信息:
当关联的资源达到阈值时,就限流自己。
当于A关联的资源B达到阈值后,就限流A自己。
设置postman频繁访问testB:
测试A可以看到A又挂了:
等线程B访问结束后,A恢复正常。
多个请求调用了同一个微服务。
直接失败,抛出异常,即上面的流控模式的测试的处理方式。
公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值。
解释下:阈值设置为10,预热时长设置为10s,那么在前10秒钟,阈值其实时10/3,每秒限制3个qps,当达到10s后,qps才会提升到10个。
作用:秒杀系统在开启的瞬间,会有很多流量上来,很可能把系统打死,预热方式就是为了保护系统,把流量慢慢的放进来,慢慢的把阙值增长到设置的阙值。
作用:用于处理间隔性突发的流量,例如消息队列。例如这样的场景:在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是第一秒直接拒绝多余的请求。
半开状态:半开的状态系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,由异常则继续打开断路器不可用。
这个200ms是平均响应时间,而不是某一次的响应时间。
后续亭子jmeter了,1s后,访问恢复正常。
上述配置意思是:每秒内的请求中百分之20都失败了,那么久进入服务降级。
请求恢复后,3秒钟之后,服务降级解决。
解释:比如某个商品被经常访问:localhost:80/get?pid=2;那么会对这条访问进行限流,但是不会对localhost:80/get?pid=3进行限流。
方法:
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false)String p1,
@RequestParam(value = "p2",required = false)String p2) {
return "----testHotKey";
}
// 兜底方法
public String deal_testHotKey(String p1, String p2, BlockException exception) {
return "----deal_testHotKey, o(╥﹏╥)o"; // sentinel的默认提示都是: Blocked by Sentinel (flow limiting)
}
配置:testHotKey这个方法的第一个参数,限制同一个值每秒访问一次,超过九进行限流,调用兜底方法
如果不设置blockHandler兜底方法,会报出错误页面:
注意:如果程序中有运行异常,并不会进入兜底方法,@SentinelResource+blockHandler注解管的只是热点key的配置(fallback会处理业务异常)。
意思就是:比如当我们的第一个参数,比如上面的p1=10时,我们希望它的阈值是一个特殊值,比如可以达到200
注意点:参数必须是基本类型或者String
上述演示的时候,我们可能会面临的问题:
新建服务提供者9003和9004;
新建消费者84。
添加pom依赖,yml文件,启动类,api等。不多说。
测试默认的轮询是否成功。
测试调用时,添加fallback注解,在程序中添加业务异常:
@RequestMapping("/consumer/fallback/{id}")
//@SentinelResource(value = "fallback")
@SentinelResource(value = "fallback",fallback ="handlerFallback")
public CommonResult<Payment> fallback(@PathVariable Long id) {
CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id,CommonResult.class,id);
if(id == 4){
throw new IllegalArgumentException("IllegalArgument ,非法参数异常...");
}else if(result.getData() == null) {
throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
public CommonResult handlerFallback(@PathVariable Long id,Throwable e) {
Payment payment = new Payment(id,"null");
return new CommonResult(444,"异常handlerFallback,exception内容: " + e.getMessage(), payment);
}
经过测试,fallback属性可以处理业务异常(不包括运行时异常),blockHandler只能处理配置违规。
@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback",blockHandler = "blockHandler")
public CommonResult<Payment> fallback(@PathVariable Long id) {
。。。
}
public CommonResult blockHandler(@PathVariable Long id,BlockException e) {
Payment payment = new Payment(id,"null");
return new CommonResult(444,"blockHandler-sentinel 限流,BlockException: " + e.getMessage(), payment);
}
经过测试,会抛出程序异常,可以验证上节结论。
@SentinelResource(value = "fallback",fallback ="handlerFallback",blockHandler = "blockHandler")
经过测试,如果在符合blockHandler的情况时,会进入兜底方法,如果不符合blockHandler的情况时,会进入blockHandler方法,也就是说:blockHandler优先级高于fallback 。
一旦我们重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化。
将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持续有效。
pom添加:
<!-- SpringCloud ailibaba sentinel-datasource-nacos 持久化需要用到-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
yml添加datasource配置:
sentinel:
transport:
#配置Sentin dashboard地址
dashboard: localhost:8080
# 默认8719端口,假如被占用了会自动从8719端口+1进行扫描,直到找到未被占用的 端口
port: 8719
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: cloudalibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow