第十四章 Sentinel实现熔断与限流
Sentinel实现熔断与限流
1. Sentinel简介
官网:GitHub - alibaba/Sentinel: A powerful flow control component enabling reliability, resilience and monitoring for microservices. (面向云原生微服务的高可用流控防护组件) 中文:introduction | Sentinel
Hystrix:需要程序员自己搭建监控平台,没有更加细粒度的流控、速率控制、服务熔断、服务降级...;而Sentinel提供了细粒度的web界面的控制操作。
Sentinel下载安装
网址:Releases · alibaba/Sentinel · GitHub Sentinel就是可以做服务降级、服务雪崩、服务熔断、服务限流。
Sentinel的后台有两部份组成: 核心库(Java客户端)不依赖任何框架/库,能够运行于所有Java运行时环境,同时对 Dubbo /Spring Cloud等框架也有较好的支持。 控制台(Dashboard)基于Spring Boot开发,打包后可以直接运行,不需要额外的Tomcat等应用容器。
Sentinel下载下来是一个jar包,运行命令:java -jar ......
访问:
默认密码和用户:sentinel
2. Sentinel初始化演示工程
2.1 Sentinel初始化监控
创建cloudalibaba-sentinel-service8401项目
-
pom文件
<dependency>
? ?<groupId>com.alibaba.cloud</groupId>
? ?<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
-
application.yaml
server:
port: 8401
?
spring:
application:
? name: cloudalibaba-sentinel-service
cloud:
? nacos:
? ? discovery:
? ? ? ?#服务注册中心
? ? ? server-addr: localhost:8848
? sentinel:
? ? transport:
? ? ? ?#配置dashboard地址
? ? ? dashboard: localhost:8080
? ? ? ?#默认端口8719,假如被占用会自动从8719开始依次+1扫描,直至找到未被古用的端口
? ? ? port: 8719
management:
endpoints:
? web:
? ? exposure:
? ? ? include: '*'
-
主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class MainApp8401 {
? ?public static void main(String[] args) {
? ? ? ?SpringApplication.run(MainApp8401.class,args);
? }
}
-
controller层
@RestController
public class FlowLimitController {
?
? ?@GetMapping("/testA")
? ?public String testA(){
? ? ? ?return "--------testA";
? }
?
? ?@GetMapping("/testB")
? ?public String testB(){
? ? ? ?return "--------testB";
? }
}
测试: Sentinel使用的是懒加载机制,需要先进行ip地址访问,才会出现:
3. Sentinel流控规则简介
流控规则:
-
资源名:唯一名称,默认请求路径
-
针对来源: Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
-
阈值类型/单机阈值:
-
QPS(每秒钟的请求数量):当调用该api的QPS达到阈值的时候,进行限流。
-
线程数:当调用该api伯的线程数达到阈值的时候,进行限流
-
-
是否集群:不需要集群
-
流控模式:
-
直接:api达到限流条件时,直接限流
-
关联:当关联的资源达到阈值时,就限流自己
-
链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】
-
-
流控效果:
-
快速失败:直接失败,抛异常
-
Warm Up:根据codeFactor (冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值
-
排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效
-
3.1 Sentinel流控-QPS直接失败
(直接->快速失败)系统默认QPS:每秒请求数,单机阈值设置为1,如果超过1则报错处理。(一秒一次可以,超出报错)
测试:
3.2 Sentinel流控-线程数直接失败
线程数:每一秒线程数到达阈值就进行限流,表示只有一个线程进行处理,如果一个线程处理来不及就会报错。
修改cloudalibaba-sentinel-service8401项目的controller层:
@RestController
public class FlowLimitController {
?
? ?@GetMapping("/testA")
? ?public String testA(){
? ? ? ?//线程数测试,模拟暂停毫秒
? ? ? ?try{
? ? ? ? ? ?TimeUnit.MICROSECONDS.sleep(8000);
? ? ? } catch (InterruptedException e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? }
? ? ? ?return "--------testA";
? }
?
? ?@GetMapping("/testB")
? ?public String testB(){
? ? ? ?return "--------testB";
? }
}
设置:
测试:
3.3 Sentinel流控-关联
关联:关联到限流条件时,直接限流。A与B关联,设置A的关联限流,只要B资源请求有限时,A会出现报错。
设置:
测试:
3.4 Sentinel流控-预热(Warm up)
流控效果:直接->快速失败(默认的流控处理)源代码com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
预热:公式->阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值。 官网:默认coldFactor为3,即请求QPS 从threshold(阈值) / 3开始,经预热时长逐渐升至设定的QPS阈值。
限流-冷启动:Home · alibaba/Sentinel Wiki · GitHub限流---冷启动 源代码:com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController
测试:
??https://live.csdn.net/v/355136
3.5 Sentinel流控-排队等待
匀速排队,让请求以均匀的速度通过,阀值类型必须设成QPS,否则无效。匀速排队( RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。详细文档可以参考流量控制–匀速器被式,具体的例子可以参见 PaceFlowDemo。
设置:
修改cloudalibaba-sentinel-service8401项目的controller层:
@RestController
@Slf4j
public class FlowLimitController {
?
? ?@GetMapping("/testA")
? ?public String testA(){
// ? ? ? //线程数测试,模拟暂停毫秒
// ? ? ? try{
// ? ? ? ? ? TimeUnit.MICROSECONDS.sleep(8000);
// ? ? ? } catch (InterruptedException e) {
// ? ? ? ? ? e.printStackTrace();
// ? ? ? }
? ? ? ?log.info(Thread.currentThread().getName()+"\t"+"....testA");
? ? ? ?return "--------testA";
? }
?
? ?@GetMapping("/testB")
? ?public String testB(){
? ? ? ?return "--------testB";
? }
}
测试:
4. Sentinel降级简介
视频使用的是1.7.0sentinel,但是自己使用sentienl1.8.6界面有不同,并且1.8.6添加更多功能,但跟着视频学习:
官网:Home · alibaba/Sentinel Wiki · GitHub焰断降级
RT(平均响应时间,秒级): 平均响应时间超出阈值且在时间窗口内通过的请求>=5,两个条件同时满足后触发降级 窗口期过后关闭断路器 ? RT最大4900(更大的需要通过-Dcsp.sentinel.statistic.max.rt=XXXX才能生效) ? 异常比列(秒级): QPS >= 5且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束言,关闭降级 ? 异常数(分钟级) 异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级
Sentinel的断路器是没有半开状态的。不会像hystrix有半开的状态,进行连接测试检查。
4.1 Sentinel降级-RT
RT:平均响应时间( DEGRADE_GRADE_RT ):当1s内持续进入5个请求,对应时刻的平均响应时间(秒级)均超过阈值(count ,以ms为单位),那么在接下的时间窗口 DegradeRule中的timewindow ,以s 为单位)之内,对这个方法的调用都会自动地熔断(抛出DegradeException )。注意Sentinel默认统计的RT上限是4900 ms,超出此阈值的都会算作4900ms,若需要变更此上限可以通过启动配置项-Dcsp.sentinel.statistic.max.rtmxxx来配置。
修改cloudalibaba-sentinel-service8401项目的controller层:
@RestController
@Slf4j
public class FlowLimitController {
?
? ?@GetMapping("/testA")
? ?public String testA(){
// ? ? ? //线程数测试,模拟暂停毫秒
// ? ? ? try{
// ? ? ? ? ? TimeUnit.MICROSECONDS.sleep(8000);
// ? ? ? } catch (InterruptedException e) {
// ? ? ? ? ? e.printStackTrace();
// ? ? ? }
? ? ? ?log.info(Thread.currentThread().getName()+"\t"+"....testA");
? ? ? ?return "--------testA";
? }
?
? ?@GetMapping("/testB")
? ?public String testB(){
? ? ? ?return "--------testB";
? }
?
? ?@GetMapping("/testD")
? ?public String testD(){
? ? ? ?try{
? ? ? ? ? ?TimeUnit.SECONDS.sleep(1);
? ? ? } catch (InterruptedException e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? }
? ? ? ?return "--------testD";
? }
}
配置:
测试:
4.2 Sentinel降级-异常比例
异常比例( DEGRADE_GRADE_EXCEPTION_RATIo):当资源的每秒请求量>= 5,并且每秒异常总数占通过量的比值超过阈值( DegradeRule中的count )之后,资源进入降级状态,即在接下的时间窗口( DegradeRule 中的 timewindow,以s为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0,1.0],代表0%- 100%。
修改cloudalibaba-sentinel-service8401项目的controller层:
@GetMapping("/testD")
? ?public String testD(){
? ? ? ?int age=10/0;
? ? ? ?return "--------testD";
? }
配置:
测试:
停止jmeter:
4.3 Sentinel降级-异常数
异常数(DEGRADE_GRADE_EXCEPTION_COUNT ):当资源近1分钟的异常数目超过阈值之后会进行熔断。注意由于统讣时间窗口是分钟级别的,若 timelWindow小于60s,则结束熔断状态后仍可能再进入熔断状态。
修改cloudalibaba-sentinel-service8401项目的controller层:
@GetMapping("/testD")
? ?public String testD(){
? ? ? ?int age=10/0;
? ? ? ?return "--------testD";
? }
配置:
测试:
5. Sentinel热点key
5.1 Sentinel热点上
热点数据限流就是频繁访问的数据,可以根据参数传递进行限流等。
热点限流源代码:com.alibaba.csp.sentinel.slots.block.BlockException
修改cloudalibaba-sentinel-service8401项目的controller层:
@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 e){
? ? ? ?return "------------deal_testHotKey";
? }
配置:
测试:(这个必须是注解绑定有效,url那个地址没有效果,不知道)
如果使用热点限流,主要加上blockHandler进行降级处理。
5.2 参数例外项
参数根据参数值进行不同的限流控制,例如p1参数值为5的时候进行限流,为其他的值就是通用的限流方式。
配置:
测试:
??https://live.csdn.net/v/355138
@SentinelResource 处理的是sentine1控制台配置的违规情况,有blockHandler方法配置的兜底处理; ? RuntimeException int age = 10/0,这个是java运行时报出的运行时异常RunTimeException,@SentinelResource不管 ? 总结 SentinelResource主管配置出错,运行出错该走异常走异常
6. 系统规则
官网:Home · alibaba/Sentinel Wiki · GitHub系统自适应限流
系统规则就相当于给整个系统添加一层流控,是给每一个api接口,但是这样实现不了细粒度的流控,所以一般不会怎么使用。
Load自适应(仅对系统的 load1作为启发指标。进行自适应系统保护。当系统load1超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR阶段)。系统容量由系统的 maxQps * minRt估算得出。设定参考值一般是cpu cores* 2.5。 ? CPU usage(1.5.0+版本):当系统CPU使用率超过阈值即触发系统保护(取值范围0.0-1.0),比较灵敏。 ? 平均RT;当单台机器上所有入口流量的平均RT达到阈值即触发系统保护,单位是毫秒。 ? 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。 ? 入口QPS:当单台机器上所有入口流量的QPS 达到阈值即触发系统保护。
测试一系统QPS: 配置:
测试:
7. SentinelResource配置
7.1 按资源名称限流+后续处理
修改cloudzlibaba-sentinel-service8401项目:
1.添加RateLimitController
@RestController
public class RateLimitController {
? ?@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服务不可用");
? }
}
配置:
测试:
流控规则是临时的。
7.2 按照Url地址限流+后续处理
修改cloudalibaba-sentinel-service8401项目:
1.修改RateLimitController:
@RestController
public class RateLimitController {
? ?@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服务不可用");
? }
? ?
? ?@GetMapping("/rateLimit/byUrl")
? ?@SentinelResource(value = "byUrl")
? ?public CommonResult byUrl(){
? ? ? ?return new CommonResult(200,"按url限流测试ok",new Payment(2020L,"serial002"));
? }
}
配置:
测试:
上面的问题:
1系统默认的,没有体现我们自己的业务要求。 2依照现有条件,我们自定义的处理方法又和业务代码耦合在一块,不直观。 3 每个业务方法都添加—个兜底的,那代码膨胀加剧。 4全局统—的处理方法没有体现。
7.3 客户自定义限流处理逻辑
创建CustomerBlockHandler类用于自定义限流处理逻辑:
public class CustomerBlockHandler {
? ?public static CommonResult handlerException1(BlockException exception){
? ? ? ?return new CommonResult(4444,"按客户自定义限流测试异常处理1,全局异常处理一");
? }
? ?public static CommonResult handlerException2(BlockException exception){
? ? ? ?return new CommonResult(4444,"按客户自定义限流测试异常处理2,全局异常处理二");
? }
}
controller层:
@GetMapping("/rateLimit/customerBlockHandler")
? ?@SentinelResource(value = "customerBlockHandler",blockHandlerClass = CustomerBlockHandler.class,
? ? ? ? ? ?blockHandler = "handlerException1")
? ?public CommonResult customerBlockHandler(){
? ? ? ?return new CommonResult(200,"按客户自定义限流测试ok",new Payment(2020L,"serial003"));
? }
配置:
测试:
@SentinelResource不支持private修饰。Sentinel主要有三个核心Api:SphU定义资源、Tracer定义统计、ContextUtil定义了上下文。
8. 服务熔断功能
sentinel整合ribbon+openfengin+fallback,实现负载均衡+远程调用+服务熔断
8.1 Sentinel+Ribbon
创建服务消费者cloudalibaba-consumer-order84项目:
-
pom文件
<dependencies>
? ? ? ?<!--后面会使用到持久化-->
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>com.alibaba.csp</groupId>
? ? ? ? ? ?<artifactId>sentinel-datasource-nacos</artifactId>
? ? ? ?</dependency>
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>com.alibaba.cloud</groupId>
? ? ? ? ? ?<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
? ? ? ?</dependency>
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>org.springframework.cloud</groupId>
? ? ? ? ? ?<artifactId>spring-cloud-starter-openfeign</artifactId>
? ? ? ?</dependency>
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>com.alibaba.cloud</groupId>
? ? ? ? ? ?<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
? ? ? ?</dependency>
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>com.yicai.springcloud</groupId>
? ? ? ? ? ?<artifactId>cloud-api-commons</artifactId>
? ? ? ? ? ?<version>1.0-SNAPSHOT</version>
? ? ? ?</dependency>
? ? ? ?<!-- ? ? ? spring-boot-web 启动类-->
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>org.springframework.boot</groupId>
? ? ? ? ? ?<artifactId>spring-boot-starter-web</artifactId>
? ? ? ?</dependency>
? ? ? ?<!-- ? ? ? spring-boot-actuator 健康监控-->
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>org.springframework.boot</groupId>
? ? ? ? ? ?<artifactId>spring-boot-starter-actuator</artifactId>
? ? ? ?</dependency>
? ? ? ?<!-- ? ? ? 热更新-->
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>org.springframework.boot</groupId>
? ? ? ? ? ?<artifactId>spring-boot-devtools</artifactId>
? ? ? ? ? ?<scope>runtime</scope>
? ? ? ? ? ?<optional>true</optional>
? ? ? ?</dependency>
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>org.projectlombok</groupId>
? ? ? ? ? ?<artifactId>lombok</artifactId>
? ? ? ? ? ?<optional>true</optional>
? ? ? ?</dependency>
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>org.springframework.boot</groupId>
? ? ? ? ? ?<artifactId>spring-boot-starter-test</artifactId>
? ? ? ? ? ?<scope>test</scope>
? ? ? ?</dependency>
? ?</dependencies>
-
yaml文件
server:
port: 84
spring:
application:
? name: nacos-order-consumer
cloud:
? nacos:
? ? discovery:
# ? ? ? server-addr: 192.168.25.153:1111
? ? ? server-addr: localhost:8848
? sentinel:
? ? transport:
? ?#配置dashboard地址
? ? ? dashboard: localhost:8080
? ?#默认端口8719,假如被占用会自动从8719开始依次+1扫描,直至找到未被古用的端口
? ? ? port: 8719
?
management:
endpoints:
? web:
? ? exposure:
? ? ? include: '*'
-
主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class OrderMain84 {
? ?public static void main(String[] args) {
? ? ? ?SpringApplication.run(OrderMain84.class,args);
? }
}
-
controller层
@RestController
@Slf4j
public class OrderController {
? ?public static final String SERVICE_URL = "http://nacos-payment-provider";
?
? ?@Resource
? ?private RestTemplate restTemplate;
?
? ?@RequestMapping("/consumer/fallback/{id}")
? ?@SentinelResource(value = "fallback")
? ?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("IllegalArgumentException,非法参数异常...");
? ? ? }else if(result.getData()==null){
? ? ? ? ? ?throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常...");
? ? ? }
? ? ? ?return result;
? }
}
-
config
@Configuration
public class ApplicationConfig {
? ?
? ?@Bean
? ?@LoadBalanced
? ?public RestTemplate getRestTemplate(){
? ? ? ?return new RestTemplate();
? }
}
创建服务提供者cloudalibaba-provider-payment9003/9004项目:
-
pom文件
<dependencies>
?
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>com.alibaba.cloud</groupId>
? ? ? ? ? ?<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
? ? ? ?</dependency>
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>com.yicai.springcloud</groupId>
? ? ? ? ? ?<artifactId>cloud-api-commons</artifactId>
? ? ? ? ? ?<version>1.0-SNAPSHOT</version>
? ? ? ?</dependency>
? ? ? ?<!-- ? ? ? spring-boot-web 启动类-->
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>org.springframework.boot</groupId>
? ? ? ? ? ?<artifactId>spring-boot-starter-web</artifactId>
? ? ? ?</dependency>
? ? ? ?<!-- ? ? ? spring-boot-actuator 健康监控-->
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>org.springframework.boot</groupId>
? ? ? ? ? ?<artifactId>spring-boot-starter-actuator</artifactId>
? ? ? ?</dependency>
? ? ? ?<!-- ? ? ? 热更新-->
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>org.springframework.boot</groupId>
? ? ? ? ? ?<artifactId>spring-boot-devtools</artifactId>
? ? ? ? ? ?<scope>runtime</scope>
? ? ? ? ? ?<optional>true</optional>
? ? ? ?</dependency>
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>org.projectlombok</groupId>
? ? ? ? ? ?<artifactId>lombok</artifactId>
? ? ? ? ? ?<optional>true</optional>
? ? ? ?</dependency>
? ? ? ?<dependency>
? ? ? ? ? ?<groupId>org.springframework.boot</groupId>
? ? ? ? ? ?<artifactId>spring-boot-starter-test</artifactId>
? ? ? ? ? ?<scope>test</scope>
? ? ? ?</dependency>
? ?</dependencies>
-
application.yml
server:
port: 9003
spring:
application:
? name: nacos-payment-provider
cloud:
? nacos:
? ? discovery:
# ? ? ? server-addr: 192.168.25.153:1111
? ? ? server-addr: localhost:8848
?
management:
endpoints:
? web:
? ? exposure:
? ? ? include: '*'
-
主启动
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003 {
? ?public static void main(String[] args) {
? ? ? ?SpringApplication.run(PaymentMain9003.class,args);
? }
}
-
controller层
@RestController
public class PaymentController {
? ?@Value("${server.port}")
? ?private String serverPort;
? ?
? ?public static HashMap<Long,Payment> hashMap=new HashMap<Long, Payment>();
? ?static {
? ? ? ?hashMap.put(1L,new Payment(1L,"1111111111111111"));
? ? ? ?hashMap.put(2L,new Payment(2L,"2222222222222222"));
? ? ? ?hashMap.put(3L,new Payment(3L,"3333333333333333"));
? }
? ?
? ?@GetMapping(value = "/paymentSQL/{id}")
? ?public CommonResult<Payment> paymentSQL(@PathVariable("id")Long id){
? ? ? ?Payment payment = hashMap.get(id);
? ? ? ?CommonResult<Payment> result=new CommonResult<>(200,"from mysql,serverPort:"+serverPort,payment);
? ? ? ?return result;
? }
}
测试:
8.2 fallback使用和blockHandler使用
fallback处理java运行时异常:
修改cloudalibaba-consumer-order84项目的controller层:
@RestController
@Slf4j
public class OrderController {
? ?public static final String SERVICE_URL = "http://nacos-payment-provider";
?
? ?@Resource
? ?private RestTemplate restTemplate;
?
? ?@RequestMapping("/consumer/fallback/{id}")
? ?@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("IllegalArgumentException,非法参数异常...");
? ? ? }else if(result.getData()==null){
? ? ? ? ? ?throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常...");
? ? ? }
? ? ? ?return result;
? }
?
? ?//fallback
? ?public CommonResult handlerFallback(@PathVariable Long id,Throwable e){
? ? ? ?Payment payment=new Payment(id,"null");
? ? ? ?return new CommonResult(444,"兜底异常handlerFallback,exception内容"+e.getMessage(),payment);
? }
}
测试:
blockHandler处理的是配置的限流报错处理:
修改cloudalibaba-consumer-order84项目的controller层:
@RestController
@Slf4j
public class OrderController {
? ?public static final String SERVICE_URL = "http://nacos-payment-provider";
?
? ?@Resource
? ?private RestTemplate restTemplate;
?
? ?@RequestMapping("/consumer/fallback/{id}")
// ? @SentinelResource(value = "fallback",fallback = "handlerFallback")
? ?@SentinelResource(value = "fallback",blockHandler = "blockHandler")
? ?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("IllegalArgumentException,非法参数异常...");
? ? ? }else if(result.getData()==null){
? ? ? ? ? ?throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常...");
? ? ? }
? ? ? ?return result;
? }
?
? ?//blockHandler
? ?public CommonResult blockHandler(@PathVariable Long id, BlockException blockException){
? ? ? ?Payment payment=new Payment(id,"null");
? ? ? ?return new CommonResult(444,"sentinel限流兜底blockHandler,exception内容"+blockException.getMessage(),payment);
? }
?
? ?//fallback
// ? 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合并处理:
修改cloudalibaba-consumer-order84项目的controller层:
@RestController
@Slf4j
public class OrderController {
? ?public static final String SERVICE_URL = "http://nacos-payment-provider";
?
? ?@Resource
? ?private RestTemplate restTemplate;
?
? ?@RequestMapping("/consumer/fallback/{id}")
? ?@SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler")
// ? @SentinelResource(value = "fallback",blockHandler = "blockHandler")
? ?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("IllegalArgumentException,非法参数异常...");
? ? ? }else if(result.getData()==null){
? ? ? ? ? ?throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常...");
? ? ? }
? ? ? ?return result;
? }
?
? ?//blockHandler
? ?public CommonResult blockHandler(@PathVariable Long id, BlockException blockException){
? ? ? ?Payment payment=new Payment(id,"null");
? ? ? ?return new CommonResult(444,"sentinel限流兜底blockHandler,exception内容"+blockException.getMessage(),payment);
? }
?
? ?//fallback
? ?public CommonResult handlerFallback(@PathVariable Long id,Throwable e){
? ? ? ?Payment payment=new Payment(id,"null");
? ? ? ?return new CommonResult(444,"兜底异常handlerFallback,exception内容"+e.getMessage(),payment);
? }
}
配置:
测试:
8.3 exceptionToIgnore忽略属性
修改cloudalibaba-consumer-order84项目的controller层:
@SentinelResource(value = "fallback",fallback = "handlerFallback",
? ? ? ? ? ?blockHandler = "blockHandler",exceptionsToIgnore = {IllegalArgumentException.class})
测试:
修改cloudalibaba-consumer-order84项目:
-
pom文件
<dependency>
? ?<groupId>org.springframework.cloud</groupId>
? ?<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
-
application.yaml
#激活sentinel对feign的支持
feign:
sentinel:
? enabled: true
-
主启动类激活@EnableFeignClients
-
service
@FeignClient(value = "nacos-payment-provider",
fallback = PaymentFallbackService.class)
public interface PaymentService {
? ?@GetMapping(value = "/paymentSQL/{id}")
? ?CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
@Component
public class PaymentFallbackService implements PaymentService{
? ?@Override
? ?public CommonResult<Payment> paymentSQL(Long id) {
? ? ? ?return new CommonResult<>(444,"服务降级返回,-----paymentfallbackservice",new Payment(id,"error"));
? }
}
-
controller
@Resource
? ?private PaymentService paymentService;
?
? ?@GetMapping(value = "/consumer/paymentSQL/{id}")
? ?public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id){
? ? ? ?return paymentService.paymentSQL(id);
? }
测试:
8.5 规则持久化
一旦我们重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化
设置:将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持续有效。
步骤(修改cloud-sentinel-service8401项目):
-
pom文件
<dependency>
? ?<groupId>com.alibaba.csp</groupId>
? ?<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
-
application.yaml
server:
port: 8401
?
spring:
application:
? name: cloudalibaba-sentinel-service
cloud:
? nacos:
? ? discovery:
? ? ? ?#服务注册中心
? ? ? server-addr: localhost:8848
? sentinel:
? ? transport:
? ? ? ?#配置dashboard地址
? ? ? dashboard: localhost:8080
? ? ? ?#默认端口8719,假如被占用会自动从8719开始依次+1扫描,直至找到未被古用的端口
? ? ? port: 8719
? ? datasource:
? ? ? ds1:
? ? ? ? nacos:
? ? ? ? ? server-addr: localhost:8848
? ? ? ? ? dataId: ${spring.application.name}
? ? ? ? ? groupId: DEFAULT_GROUP
? ? ? ? ? data-type: json
? ? ? ? ? rule-type: flow
-
配置
[
? {
? ? ? "resource":"/rateLimit/byUrl",
? ? ? "limitApp":"default",
? ? ? "grade":1,
? ? ? "count":1,
? ? ? "streategy":0,
? ? ? "controlBehavior":0,
? ? ? "clusterMode":false
? }
]
resource:资源名称; limitApp:来源应用; grade:阈值类型,0表示线程数,1表示QPS; count:单机阈值; strategy:流控模式,0表示直接,1表示关联,2表示链路; controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待; clusterMode是否集群。
测试:(启动8401)观察(初次可能需要调用接口,sentinel界面才会出现)
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!