spring cloud alibaba sentinel 运行及简单使用
1.官网
英文:https://github.com/alibaba/Sentinel 中文:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D 文档:https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel
2.简要说明
Sentinel是阿里开源的项目,提供了流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。2012年,Sentinel诞生于阿里巴巴,其主要目标是流量控制。2013-2017年,Sentinel迅速发展,并成为阿里巴巴所有微服务的基本组成部分。 它已在6000多个应用程序中使用,涵盖了几乎所有核心电子商务场景。2018年,Sentinel演变为一个开源项目。2020年,Sentinel Golang发布。更详细的还是看官网最好。
3.sentinel的组成
Sentinel 的使用可以分为两个部分:
控制台(Dashboard):控制台主要负责管理推送规则、监控、集群限流分配管理、机器发现等。
核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 7 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持
4.sentinel的下载
https://github.com/alibaba/Sentinel/releases
这里选择的1.7.0版本
4.运行
下载下来是一个jar包,需要JDK1.8环境
执行命令 java -jar sentinel-dashboard-1.7.0.jar
默认端口是8080,注意端口冲突问题
5.访问sentinel控制台
http://localhost:8080/#/login
默认账号密码都是sentinel
出现此界面,表示sentinel下载运行成功
6.使用sentinel来保护项目
上面,我们运行sentinel成功,下面,我们在项目中做一个最简单的使用。注册中心使用的nacos。
6.1创建一个模块
6.2依赖
nacos依赖和sentinel依赖
<!--服务注册-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency> <!--sentinel持久化-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency> <!--sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
完整
<dependencies> <!--服务注册-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency> <!--sentinel持久化-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency> <!--sentinel-->
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <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> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
</dependencies>
6.3配置文件
server:
port: 8401 spring:
application:
name: cloudalibaba-sentinel-service #将会作为注册到注册中心的服务名称
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos注册中心的地址
sentinel:
transport:
dashboard: localhost:8080 #sentinel控制台地址
port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
management:
endpoints:
web:
exposure:
include: '*'
这里,配置了nacos注册中心地址,配置了sentinel的相关配置
6.4主启动类
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /**
* @Classname PaymentMain9001
* @Description TODO
* @Date 2021/6/18 0018 下午 2:20
* @Created by jcc
*/
@SpringBootApplication
@EnableDiscoveryClient
public class MainApp8401 {
public static void main(String[] args) {
SpringApplication.run(MainApp8401.class,args);
}
}
6.5业务类
业务类提供两个简单的接口
package com.atguigu.springcloud.controller; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; /**
* @Classname FlowLimitController
* @Description TODO
* @Date 2021/6/24 0024 下午 4:11
* @Created by jcc
*/ @RestController
public class FlowLimitController
{
@GetMapping("/testA")
public String testA() {
return "------testA";
} @GetMapping("/testB")
public String testB() {
return "------testB";
}
}
6.6启动
启动nacos,启动sentinel,启动该模块,登录sentinel控制台
访问testA和testB接口
刷新 sentinel控制台
此时,我们可以看到sentinel控制台出现了testA和testB。
左侧菜单提供了很多的功能,这个后面再一一讲解
7.流量控制
https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6
流量控制可以对特定的请求资源进行流量控制,设置相应的规则,当访问量超出规则时,会对这个请求进行流量控制,直接返回。
下图是sentinel控制台-流量控制页面
选择流控规则,点击新增流控规则,点击高级选项
7.1流控规则内容说明
1)资源名
唯一名称,默认请求路径。也可以通过注解配置
2)针对来源
针对哪个调用者进流量控制,填写服务名称即可,默认default-不区分来源,针对所有调用者
3)阀值类型
QPS:每秒请求数,但调用量大于这个值的时候,进行限流
线程数:处理该请求的线程数,处理该API的线程数大于这个值的时候,进行限流
4)是否集群
5)流控模式
直接:达到阀值时,直接限流
关联:本请求达到阀值,对和他相关的请求进行限流
链路:只记录指定链路上的流量,如果达到阀值,则限流。指定链路,比如/testA有很多地方调用了,我只限制testB对他的调用为1秒最多调用1次,其它的队testA的调用则不管
6)流控效果-阀值类型QPS才有这个选项
快速失败:达到阀值,直接失败
Warm Up:预热。
排队等待:允许排队,让请求匀速通过
下面来一一测试不同的配置的效果
7.1.1流量控制-测试1
对/testA进行流量控制
阀值类型为QPS
每秒请求书限制为1个
流控模式为直接
流控效果为快速失败
也就是设置testA1秒内访问量限制为1次,超过直接返回
添加成功后,访问testA这个请求
1)访问方式:浏览器直接访问一次
成功
2)访问方式:一秒内快速访问两次
第一次请求成功,第二次请求失败,sentinel返回错误信息,这个错误信息是sentinel自带的,如何自定义返回信息,后面再说
因为我们设置了1秒内访问一次的阀值,这里超过了阀值,所以被限流了
7.1.2流量控制-测试
对/testA进行流量控制
阀值类型为线程数
线程数限制为1
流控模式为直接
流控效果无法选择
也就是设置testA访问线程数为1,超出直接返回
直接对上面的规则编辑就可以,编辑完成后,立即生效
访问testA这个请求
1)访问方式:浏览器1秒内直接访问一次或者多次
成功
这就是线程数和QPS的区别,QPS是对请求数进行限制,线程数是对线程进行限制,只提供1个线程来处理这个请求,不管请求数多少,只要这个线程处理的过来,就会处理
2)访问方式:在浏览器1秒内快速访问这个请求一次
对接口testA做一点点修改,让他等待2s
@GetMapping("/testA")
public String testA() throws InterruptedException {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName());
return "------testA";
}
3)访问方式:在浏览器1秒内快速访问这个请求多次
第二次立马返回失败信息,因为我们设置了1个线程的阀值,超过这个阀值,就被限流了
7.1.3流量控制-测试
对/testA进行流量控制
阀值类型为QPS
单机阀值限制为1
流控模式为关联-关联对象为/testB
流控效果快速失败
当testB超出阀值时,testA将被限制
设置testB访问1秒限制1次,超过的话限制testA,直接返回
1)浏览器分别访问testA 和testB一次
把testA睡眠2秒的代码去掉
@GetMapping("/testA")
public String testA() throws InterruptedException {
System.out.println(Thread.currentThread().getName());
return "------testA";
} @GetMapping("/testB")
public String testB() {
return "------testB";
}
成功
2)浏览器1秒内访问testB多次,再访问testA
当testB的访问超过设定的阀值1秒1次的访问量时,testA被限流
7.1.4流量控制-测试
对/testA进行流量控制
阀值类型为QPS
单机阀值限制为1
流控模式为链路
流控效果快速失败
对testB调用testA进行限制,1秒内testB最多允许调用testA1次,超多则限流,直接返回。其它的对testA的调用不做限制
7.1.5流量控制-测试
对/testA进行流量控制
阀值类型为QPS
单机阀值限制为6
流控模式为直接
流控效果快速失败
预热时长为5秒
这里对testA进行限流,阀值为每秒6次,流控效果为warm up,时长为5秒。这里就有一个过程,最开始的阀值不是6,而是阀值6除以冷加载因子(默认为3),也就是说刚开始阀值是2,当请求量进来超过2时,超过的请求被限制直接返回。经过5秒后,阀值变为6。这种模式适合秒杀这种,访问量平常很低或者没有,某一刻突然大量的访问。这样保护服务,不让它被突然的大量访问压死。
1)浏览器访问testA一次
成功
2)快速访问testA,每秒大于2次,连续访问8秒
在前5秒的访问中,每秒最多只能访问两次,超过的被限制直接返回,过了5秒后,每秒访问量不超过6次,均可以返回。说明前5秒阀值是2,超过5秒后,阀值变为6了
7.1.6流量控制-测试
对/testA进行流量控制
阀值类型为QPS
单机阀值限制为2
流控模式为直接
流控效果排队等待
超时时间为1秒
这里限制testA每秒2次的访问量,超过的,排队等待,等待超时时间为1秒
1)测试,使用测试软件发送请求,发送10次请求,间隔时间为0.1秒
@GetMapping("/testA")
public String testA() throws InterruptedException {
System.out.println(System.currentTimeMillis() + "---" + Thread.currentThread().getName());
return "------testA";
}
控制台打印结果,每次打印时间间隔大致为0.5秒,说明请求以0.5秒一次的速度通过
1624867018539---http-nio-8401-exec-2
1624867019039---http-nio-8401-exec-1
1624867019537---http-nio-8401-exec-4
1624867020037---http-nio-8401-exec-5
1624867020539---http-nio-8401-exec-6
1624867021037---http-nio-8401-exec-7
1624867021538---http-nio-8401-exec-8
1624867022037---http-nio-8401-exec-9
1624867022538---http-nio-8401-exec-10
1624867023039---http-nio-8401-exec-3
8.熔断降级
https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用
现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。
8.1策略
1)RT:1秒内,请求数目大于最小请求数目(默认为5),且平均的响应时长大于设置的时长,服务熔断降级,时间窗口指的是熔断的时间
2)异常比例:1秒内,请求数目大于最小请求数目(默认为5),异常比例大于设置比例,服务熔断降级,时间窗口指的是熔断的时间
3)异常数:1分钟内,请求数大于最小请求数目(默认5),且请求异常数大于设置的异常数,服务熔断降级,时间窗口指的是熔断的时间。
8.热点参数限流
https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81
前面流量控制是针对某个请求。这里可以进行进一步的细化。设置当某个请求附带哪个参数的时候,才进行限流。
8.1写一个带参数接口
接口定义了两个参数,id和name
@GetMapping("/testD")
@SentinelResource(value = "testD")
public String testD(@RequestParam(value = "id",required = false) String id, @RequestParam(value = "name",required = false) String name) {
return "------testD-----id=" + id + "----name=" + name ;
}
注意,这里使用到了@SentinelResource注解,这个注解这里value属性是定义资源名字
8.2配置规则
配置对testD进行限流,只有当他带有第一个参数id时,才进行限流,每秒限流1次访问。注意,这里使用的资源名是testD(@SentinelResource注解配置的资源名),而不是/testD(资源路径)。因为我发现不使用@SentinelResource注解定义资源名字,直接使用路径配置,不生效。
1)测试1
浏览器1秒内访问testD接口多次,不带参数,每次都能成功返回
2)测试2
浏览器1秒内访问testD接口多次,携带参数name,每次都能成功返回
3)测试3
浏览器1秒内访问testD接口多次,携带参数id,限流
8.3自定义限流时返回信息
上面限流直接返回的是错误页面,不友好,可以使用@SentinelResource设置返回信息
在@SentinelResource注解添加了属性blockHandler,这个属性就是指当限流时,调用哪个方法去处理
@GetMapping("/testD")
@SentinelResource(value = "testD",blockHandler = "myResult")
public String testD(@RequestParam(value = "id",required = false) String id, @RequestParam(value = "name",required = false) String name) {
return "aaaa------testD-----id=" + id + "----name=" + name ; }
限流时处理的方法,方法名是blockHandler属性,该方法和上面testD的返回值类型需要一样,参数列表需要和testD一样,且需要多一个参数BlockException
public String myResult(String id, String name, BlockException exception){
return "限流了a"; }
此时,在1秒内返回多次,页面返回的就是处理方法的返回值
8.4高级设置-设置参数值
现在的规则是,请求testD带有参数id且id不等于1的时候,1秒限制1次访问,当id为1的时候,限制1秒访问5次
1)测试
1秒内访问testD两次,id不等于1,第二次就被限流了
2)测试
1秒内访问testD两次,id=1,成功
3)测试
1秒内访问testD多次(大于5),id=1,超过5次时,限流
9.系统自适应限流
前面讲的限流都是针对某一个资源的,如果要针对整个系统,可以配置系统规则。
这里具体的配置例子就不做了。
10.注解@SentinelResource
上面用到了它的两个属性
value:资源名
blockHandler:处理方法
下面会用到它的CustomerBlockHandler属性
下面有两个接口testC和testD,他们的处理方法分别为myResult1和myResult2,处理方法和业务代码在一起
@GetMapping("/testC")
@SentinelResource(value = "testC",blockHandler = "myResult1")
public String testC(@RequestParam(value = "id",required = false) String id, @RequestParam(value = "name",required = false) String name) {
return "------testC-----id=" + id + "----name=" + name ;
} @GetMapping("/testD")
@SentinelResource(value = "testD",blockHandler = "myResult2")
public String testD(@RequestParam(value = "id",required = false) String id, @RequestParam(value = "name",required = false) String name) {
return "aaaa------testD-----id=" + id + "----name=" + name ; } public String myResult1(String id, String name, BlockException exception){
return "testC限流了"; } public String myResult2(String id, String name, BlockException exception){
return "testD限流了"; }
把处理方法分离出去
1)创建一个类,名字随便取,把两个处理方法移到里面去
方法必须是静态
package com.atguigu.springcloud.controller; import com.alibaba.csp.sentinel.slots.block.BlockException; /**
* @Classname MyHandler
* @Description TODO
* @Date 2021/6/29 0029 下午 4:38
* @Created by jcc
*/
public class CustomerBlockHandler {
public static String myResult1(String id, String name, BlockException exception){
return "myhandler-testC限流了";
} public static String myResult2(String id, String name, BlockException exception){
return "myhandler-testD限流了"; }
}
2)@SentinelResource添加属性blockHandlerClass
这样子处理方法就可以先找到刚才创建的类CustomerBlockHandler .class,再找到里面的具体的处理方法。这样子,处理方法和业务就分开了。
@GetMapping("/testC")
@SentinelResource(value = "testC",blockHandlerClass = CustomerBlockHandler.class ,blockHandler = "myResult1" )
public String testC(@RequestParam(value = "id",required = false) String id, @RequestParam(value = "name",required = false) String name) {
return "------testC-----id=" + id + "----name=" + name ;
} @GetMapping("/testD")
@SentinelResource(value = "testD",blockHandlerClass = CustomerBlockHandler.class ,blockHandler = "myResult2")
public String testD(@RequestParam(value = "id",required = false) String id, @RequestParam(value = "name",required = false) String name) {
return "aaaa------testD-----id=" + id + "----name=" + name ; }
下面我们介绍下fallback属性和blockHandler属性的区别
fallback是对系统runtimeexception作出处理,blockHandler是对违反sentinel配置的一系列规则作出处理
我创建两个服务提供者9003和9004,一个服务调用者84
10.1创建服务提供者9003
10.1.1创建模块
10.1.2依赖
<dependencies> <dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency> <dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <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> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
</dependencies>
10.1.4配置文件
server:
port: 9003 spring:
application:
name: nacos-payment-provider #将会作为注册到注册中心的服务名称
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址 management:
endpoints:
web:
exposure:
include: '*'
10.1.5启动类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain9003.class,args);
}
}
10.1.6业务类
@RestController
public class PaymentController
{
@Value("${server.port}")
private String serverPort; public static HashMap<Long, Payment> hashMap = new HashMap<>();
static{
hashMap.put(1L,new Payment(1L,"28a8c1e3bc2742d8848569891fb42181"));
hashMap.put(2L,new Payment(2L,"bba8c1e3bc2742d8848569891ac32182"));
hashMap.put(3L,new Payment(3L,"6ua8c1e3bc2742d8848569891xt92183"));
} @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;
} }
10.2 服务提供者9004的创建和9003除了端口都一样
10.3服务消费者84的创建
10.3.1创建模块
10.3.2 依赖
<dependencies> <dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency> <dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency> <dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency> <dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <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> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
</dependencies>
10.3.3配置文件
server:
port: 84 spring:
application:
name: nacos-order-consumer #将会作为注册到注册中心的服务名称
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址
sentinel:
transport:
dashboard: localhost:8080 #sentinel控制台地址
port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
service-url:
nacos-user-service: http://nacos-payment-provider
10.3.4主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain84 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain84.class,args);
}
}
10.3.5业务类
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
package com.atguigu.springcloud.controller; import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; @RestController
@Slf4j
public class CircleBreakerController { public static final String SERVICE_URL = "http://nacos-payment-provider"; @Resource
private RestTemplate restTemplate; @RequestMapping("/consumer/fallback/{id}")
//@SentinelResource(value = "fallback") //没有配置
//@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
@SentinelResource(value = "fallback",blockHandler = "blockHandler",fallback = "handlerFallback") //blockHandler只负责sentinel控制台配置违规
// @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",
// exceptionsToIgnore = {IllegalArgumentException.class})
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
public CommonResult blockHandler(@PathVariable Long id,BlockException blockException) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(),payment);
} }
10.4测试
启动9003和9004
在sentinel配置规则1秒内只能访问1次
1)84的业务类里面的注解使用@SentinelResource(value = "fallback") //这里没有配置fallback和blockHandler属性
#访问http://localhost:84/consumer/fallback/1,正常
#访问http://localhost:84/consumer/fallback/4,返回非法参数异常报错页面
#访问http://localhost:84/consumer/fallback/5,返回空指针异常报错页面
#1秒内访问http://localhost:84/consumer/fallback/1多次,返回错误页面
2)84的业务类里面的注解使用@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback负责业务异常 注意,修改这个配置,如果重启了84模块,需要重新在sentinel控制台添加配置1秒最多访问一次
#访问http://localhost:84/consumer/fallback/1,正常
#访问http://localhost:84/consumer/fallback/4,返回fallback处理方法信息
#访问http://localhost:84/consumer/fallback/5,返回fallback处理方法信息
#1秒内访问http://localhost:84/consumer/fallback/1多次,返回错误页面
以上测试说明,fallback属性对页面异常进行了处理,对于超出sentinel规则没有做出处理
3)84的业务类里面的注解使用@SentinelResource(value = "fallback",blockHandler = "blockHandler")//blockHandler 负责超出sentinel规则的处理
#访问http://localhost:84/consumer/fallback/1,正常
#访问http://localhost:84/consumer/fallback/4,返回错误页面
#访问http://localhost:84/consumer/fallback/5,返回错误页面
#1秒内访问http://localhost:84/consumer/fallback/1多次,返回blockHandler处理信息
4)@SentinelResource(value = "fallback",blockHandler = "blockHandler",fallback = "handlerFallback")
采用这样的配置,业务异常和超出sentinel规则都会被处理
5)@SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler", exceptionsToIgnore = {IllegalArgumentException.class})
在4的基础上加了 exceptionsToIgnore属性,就是说fallback对业务异常的处理,忽略IllegalArgumentException这个异常,也就是发生IllegalArgumentException异常时,fallback不做处理
#访问http://localhost:84/consumer/fallback/4,返回非法参数异常报错页面
#访问http://localhost:84/consumer/fallback/5,返回fallback处理方法信息
10.5fallback处理方法和业务逻辑解耦
和blockHandler属性使用blockHandlerClass属性把处理方法放到一个专门的类里面,fallback属性的处理的方法同样可以通过fallbackClass属性放到一个单独的类里面,具体参考前面的blockHandler的处理。
11.sentinel配置的持久化
11.1简要的持久化
这种持久化,是吧sentinel的配置放到nacos去配置,而不是在sentinel控制台配置好,自动持久化到nacos,配置起来比较麻烦
https://blog.csdn.net/wangjinb/article/details/107559200
11.2修改sentinel来实现持久化
https://blog.csdn.net/weixin_42211601/article/details/113062732?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_baidulandingword-1&spm=1001.2101.3001.4242
膜拜大神操作-试着弄了一下,好用
spring cloud alibaba sentinel 运行及简单使用的更多相关文章
- Spring Cloud Alibaba | Sentinel: 分布式系统的流量防卫兵初探
目录 Spring Cloud Alibaba | Sentinel: 分布式系统的流量防卫兵初探 1. Sentinel 是什么? 2. Sentinel 的特征: 3. Sentinel 的开源生 ...
- Spring Cloud Alibaba | Sentinel: 服务限流基础篇
目录 Spring Cloud Alibaba | Sentinel: 服务限流基础篇 1. 简介 2. 定义资源 2.1 主流框架的默认适配 2.2 抛出异常的方式定义资源 2.3 返回布尔值方式定 ...
- Spring Cloud Alibaba | Sentinel: 服务限流高级篇
目录 Spring Cloud Alibaba | Sentinel: 服务限流高级篇 1. 熔断降级 1.1 降级策略 2. 热点参数限流 2.1 项目依赖 2.2 热点参数规则 3. 系统自适应限 ...
- Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵进阶实战
Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵进阶实战 在阅读本文前,建议先阅读<Spring Cloud Alibaba | Sentinel:分布式系 ...
- Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵动态限流规则
Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵动态限流规则 前面几篇文章较为详细的介绍了Sentinel的使用姿势,还没看过的小伙伴可以访问以下链接查看: &l ...
- Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵基础实战
Spring Cloud Alibaba | Sentinel:分布式系统的流量防卫兵基础实战 Springboot: 2.1.8.RELEASE SpringCloud: Greenwich.SR2 ...
- Spring Cloud Alibaba Sentinel对Feign的支持
Spring Cloud Alibaba Sentinel 除了对 RestTemplate 做了支持,同样对于 Feign 也做了支持,如果我们要从 Hystrix 切换到 Sentinel 是非常 ...
- Spring Cloud Alibaba Sentinel对RestTemplate的支持
Spring Cloud Alibaba Sentinel 支持对 RestTemplate 的服务调用使用 Sentinel 进行保护,在构造 RestTemplate bean的时候需要加上 @S ...
- 0.9.0.RELEASE版本的spring cloud alibaba sentinel+feign降级处理实例
既然用到了feign,那么主要是针对服务消费方的降级处理.我们基于0.9.0.RELEASE版本的spring cloud alibaba nacos+feign实例添油加醋,把sentinel功能加 ...
- 0.9.0.RELEASE版本的spring cloud alibaba sentinel限流、降级处理实例
先看服务提供方的,我们在原来的sentinel实例(参见0.9.0.RELEASE版本的spring cloud alibaba sentinel实例)上加上限流.降级处理,三板斧只需在最后那一斧co ...
随机推荐
- 2022-11-10 Acwing每日一题
本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的.同时也希望 ...
- 钉钉dingtalk=6.3.5版本RCE复现
看到网上公开了钉钉RCE的利用方式,第一时间来复现一下. 钉钉dingtalk=6.3.5版本RCE复现 免责声明: 影响版本: 漏洞POC: 漏洞复现: 存在漏洞版本下载地址: 免责声明: 本文章仅 ...
- 重新认识下JVM级别的本地缓存框架Guava Cache(2)——深入解读其容量限制与数据淘汰策略
大家好,又见面了. 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面.如果感兴趣,欢迎关注以获取后续更新. 通过<重新认识下JVM级别的本地 ...
- psutil.AccessDenied: psutil.AccessDenied
解决办法 import psutil for proc in psutil.process_iter(): try: print(proc.name()) except (psutil.NoSuchP ...
- Day31面向对象之魔法方法
Day31面向对象之魔法方法 类的常用魔法方法如下 序号 双下方法 触发条件 1 init 对象添加独有数据的时候自动触发 2 str 对象被执行打印操作的时候自动触发 3 call 对象加括号调用的 ...
- 使用echarts(可视化图表库)
一:echarts 1.简介 一个基于 JavaScript 的开源可视化图表库 echarts官网使用教程: https://echarts.apache.org/zh/index.html 2.e ...
- java中继承的内存分析
本文主要讲述java中继承的内存分析. 示例1,代码如下: public class EncapsulationTest { public static void main(String[] args ...
- 8个Spring事务失效的场景,你碰到过几种?
前言 作为Java开发工程师,相信大家对Spring种事务的使用并不陌生.但是你可能只是停留在基础的使用层面上,在遇到一些比较特殊的场景,事务可能没有生效,直接在生产上暴露了,这可能就会导致比较严重的 ...
- texlive编译lshort-zh-cn
项目 lshort-zh-cn是一篇latex的中文文档,本身也是latex编写的. 项目地址:https://github.com/ctex-org/lshort-zh-cn 编译 texlive打 ...
- Triple 协议支持 Java 异常回传的设计与实现
作者:Apache Dubbo Contributor 陈景明 背景 在一些业务场景, 往往需要自定义异常来满足特定的业务, 主流用法是在catch里抛出异常, 例如: public void dea ...