各位小伙伴们大家好,欢迎来到这个小扎扎的spring cloud专栏,在这个系列专栏中我对B站尚硅谷阳哥的spring cloud教程进行一个总结,鉴于 看到就是学到、学到就是赚到 精神,这波依然是血赚 ┗|`O′|┛
💡Sentinel知识点速览
- 🍹 @SentinelResource注解
- 🍸 如何使用@SentinelResource
- 🍸 代码优化
- 🍹 进阶属性配置
- 🍸 fallback和blockHandler
- 🍸 OpenFeign熔断
- 🍹 配置持久化
🍹 @SentinelResource注解
之前有关Sentinel的案例中,一旦违反限流规则后,都是用sentinel系统默认的提示: Blocked by Sentinel (flow limiting),我们还可以使用@SentinelResource注解来实现像hystrix一样的兜底降级方法
🍸 如何使用@SentinelResource
只需要使用@SentinelResource注解,value属性为保证唯一使用映射名,blockHandler使用的是兜底方法的名,兜底方法的参数列表上也要加上BlockException对象
@GetMapping("/byResource")
@SentinelResource(value = "byResource", blockHandler = "handleException")
public CommonResult byResource() {return new CommonResult(200, "按资源名称限流测试OK", new Payment(2020L, "serial001"));
}public CommonResult handleException(BlockException exception) {return new CommonResult(444, exception.getClass().getCanonicalName() + "\t 服务不可用");
}
@SentinelResource注解只能对不符合配置规则的异常进行熔断降级,但是如果出现其他异常(运行时异常…)还是会直接返回错误页面
此时,超出阈值之后就会调用兜底方案
规则配置的资源名称:如果是映射路径的话降级就会返回默认的页面,就算下面 @SentinelResource注解配置的有兜底方案也不会执行;如果是@SentinelResource注解的value值,有兜底方案就会执行兜底,没有的话返回默认
🍸 代码优化
上述的代码编辑像极了hystrix,每一个方法都要对应一个兜底方案,显得接口和兜底方案耦合度很高
定义一个公共的兜底方案类CustomerBlockHandler,里面有很多的兜底方案,兜底方案定义的时候要使用static修饰
public class CustomerBlockHandler {public static CommonResult handlerException1(BlockException exception) {return new CommonResult(4444, "按客戶自定义,global handlerException----1");}public static CommonResult handlerException2(BlockException exception) {return new CommonResult(4444, "按客戶自定义,global handlerException----2");}
}
controller中的接口如果想使用该类中的某个方法作为兜底方法的话,就可以使用@SentinelResource注解配置(以handlerException2为例)
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",blockHandlerClass = CustomerBlockHandler.class,blockHandler = "handlerException2")
public CommonResult customerBlockHandler() {return new CommonResult(200, "按客戶自定义", new Payment(2020L, "serial003"));
}
🍹 进阶属性配置
🍸 fallback和blockHandler
学习完sentinel的流控、熔断、热点配置之后,项目中的异常大概就能被分为两种,一种是业务代码出现的异常诸如运行时异常等,还有一种就是不符合sentinel规则的BlockException。对应这两种异常,@SentinelResource注解有fallback和blockHandler两种属性可以分别指定兜底方案
如果@SentinelResource注解中设置哪个属性的话,哪种异常就会走配置的兜底方案方法。都不设置的话就是业务异常走默认的Whitelabel Error Page,或者sentinel规则异常的默认提示: Blocked by Sentinel (flow limiting)。都设置的话,两种异常都满足的情况下走blockHandler的兜底方案
异常忽略属性
异常忽略属性exceptionsToIgnore可以配置可忽略的异常类,也就是说当程序出现该异常时就算配置了fallback也不会走对应的兜底方案。完整的@SentinelResource注解参考如下代码
@SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler",exceptionsToIgnore = {IllegalArgumentException.class, IndexOutOfBoundsException.class})
🍸 OpenFeign熔断
在学习如何使用sentinel进行OpenFeign的熔断之前,先让我们复习一下OpenFeign服务调用的使用流程:
(1)引入相关依赖
<!--SpringCloud openfeign -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
(2)配置文件激活Sentinel对OpenFeign的支持(只有使用sentinel进行OpenFeign的熔断才需配置,其他情况下使用OpenFeign配置文件无需进行特有配置)
# 激活Sentinel对Feign的支持
feign:sentinel:enabled: true
(3)主启动类开启OpenFeign支持
@EnableFeignClients
(4)service接口使用@FeignClient注解的value指定调用接口所在微服务名,fallback 指定兜底方案, @GetMapping注解指定调用接口的映射路径,接口定义和 @GetMapping注解直接从被调用接口controller方法上注解复制即可
@FeignClient(value = "nacos-payment-provider", fallback = PaymentFallbackService.class)
public interface PaymentService {@GetMapping(value = "/paymentSQL/{id}")CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
(5)fallback 指定的兜底方案,@Component注解注册进spring容器,实现原接口后重写方法为兜底方案
@Component
public class PaymentFallbackService implements PaymentService {@Overridepublic CommonResult<Payment> paymentSQL(Long id) {return new CommonResult<>(44444, "服务降级返回,---PaymentFallbackService", new Payment(id, "errorSerial"));}
}
(6)controller接口正常调用service接口的方法
@Resource
private PaymentService paymentService;@GetMapping(value = "/consumer/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {return paymentService.paymentSQL(id);
}
🍹 配置持久化
sentinel中配置的流控、熔断、热点key规则,一旦应用进行重启之后就会消失,但是生产开发的时候需要将这些配置规则进行持久化,避免很多的配置规则再重启后重新配置。这又使用到了Nacos
将sentinel规则持久化进nacos
第一步: 引入相关依赖
<!--SpringCloud ailibaba sentinel-datasource-nacos-->
<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
第二步: 配置文件配置数据库相关
spring:cloud:sentinel:datasource:ds1:nacos:server-addr: localhost:8848dataId: cloudalibaba-sentinel-servicegroupId: DEFAULT_GROUPdata-type: jsonrule-type: flow
第三步: 根据配置文件的dataId值在nacos新建一个配置,配置的值为sentinel规则对应的值
[{"resource": "/rateLimit/byUrl","limitApp" : "default","grade": 1,"count": 1,"strategy": 0,"controlBehavior" : 0,"clusterMode" : false}
]
resource: sentinel的资源名;
limitApp: 来源应用;
grade: 阈值类型,0表示线程数,1表示QPS;
count: 单机阈值;
strategy: 流控模式,0表示直接,1表示关联,2表示链路;
controlBehavior: 流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
clusterMode: 是否集群。
这样配置上之后就可以实现sentinel规则的持久化,也就是说重启服务之后规则还在,但是只限配置之后的sentinel的规则,未配置的规则依然会在重启之后消失