Spring Cloud在使用Sentinel进行服务降级和熔断时,如果同时配置了
fallback
和blockHandler
,则在服务熔断后,抛出的BlockException
不会再fallback
逻辑中执行,而是在blockHandler
逻辑中执行。
首先来看只配置了fallback的情况,接口代码如下
// 批量读取
@GetMapping("/getBatch")
@SentinelResource(value = "getTemplateInBatch"
, fallback = "getTemplateInBatch_fallback")
public Map<Long, CouponTemplateInfo> getTemplateInBatch(@RequestParam("ids") Collection<Long> ids){
// 如果服务熔断,则不会打印以下日志,直接进入服务降级getTemplateInBatch_fallback方法中
log.info("getTemplateInBatch: {}", JSON.toJSONString(ids));
// 添加条件,如果满足则手动抛出一个运行时异常
if(ids.contains(Long.valueOf(2))) {
throw new RuntimeException("测试sentinel熔断");
}
return this.couponTemplateService.getTemplateInfoMap(ids);
}
// getTemplateInBatch服务降级方法
public Map<Long, CouponTemplateInfo> getTemplateInBatch_fallback(Collection<Long> ids){
log.info("接口被降级了");
return Maps.newHashMap();
}
// getTempalteInBatch限流后方法
public Map<Long, CouponTemplateInfo> getTemplateInBatch_block(Collection<Long> ids,BlockException exception){
log.info("接口被限流");
return null;
}
配置一个Sentinel熔断规则,即在10秒内5次及以上请求getTemplateInBatch
资源,如果异常次数比率达到了60%,则服务熔断10秒
我们通过postman或者编写测试脚本对/getBatch
接口进行测试,控制台打印日志如下
通过上面的日志可以看到,在前5次请求中打印了getTemplateInBatch: [2]
日志,说明执行了原方法,在第6次时因为满足了熔断条件,因此没有执行原方法,而是直接执行服务降级方法。这说明只配置fallback
时,服务熔断后会进入fallback
逻辑中进行处理。
接下来,在@SentinelResource注解中添加blockHandler属性
@GetMapping("/getBatch")
@SentinelResource(value = "getTemplateInBatch"
, fallback = "getTemplateInBatch_fallback"
, blockHandler = "getTemplateInBatch_block")
public Map<Long, CouponTemplateInfo> getTemplateInBatch(@RequestParam("ids") Collection<Long> ids){
// 如果服务熔断,则不会打印以下日志,直接进入服务降级getTemplateInBatch_fallback方法中
log.info("getTemplateInBatch: {}", JSON.toJSONString(ids));
// 添加条件,如果满足则手动抛出一个运行时异常
if(ids.contains(Long.valueOf(2))) {
throw new RuntimeException("测试sentinel熔断");
}
return this.couponTemplateService.getTemplateInfoMap(ids);
}
并在Sentinel控制台中增加一条流量规则
重启应用后再次进行测试
可以看到,在同时配置了fallback
和blockHandler
的情况下,当服务熔断后,直接进入了blockHandler
逻辑中处理,而没有进入fallback
,因此如果同时配置了blockHandler
和fallback
,则BlockException只会进到blockHandler
处理逻辑中(熔断后不会再进入原方法中,不会执行throw new RuntimeException,而是抛出BlockException)。