文章目录
实现熔断与限流,就是Hystrix
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e1a79e02ae38fa6fbd26ce4c219d4d52.png#pic_center)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/495c625fe49ce958812a0a12c7038374.png#pic_center)
1. 使用sentinel
1,下载sentinel的jar包(https://github.com/alibaba/Sentinel/releases)
2,运行sentinel
由于是一个jar包,所以可以直接java -jar sentinel-dashboard-1.8.0.jar在cmd窗口运行
注意,默认sentinel占用8080端口
3,访问sentinel,用户和密码都是 sentinel
http://localhost:8080
2. 微服务整合sentinel
1,启动Nacos后台(bin目录下双击startup.cmd)和Sentinel后台
2,新建一个项目cloudalibaba-sentinel-service8401,主要用于被sentinel监控
-
pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloudalibaba-sentinel-service8401</artifactId> <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.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>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>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.6.3</version> </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> </project>
-
配置文件
server: port: 8401 spring: application: name: cloudalibaba-sentinel-service cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: dashboard: localhost:8080 port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口 management: endpoints: web: exposure: include: '*'
-
主启动类
4.controller
5.到这里就可以启动8401
此时我们到sentinel中查看,发现并8401的任何信息
是因为,sentinel是懒加载,需要我们执行一次访问,才会有信息
访问http://localhost:8401/testB
或者http://localhost:8401/testA
,之后才会在Sentinel客户端显示信息.
6.可以看到.已经开始监听了
3. sentinel的流控规则
流量限制控制规则
第一种:点击簇点链路下对应资源名(如/testA)的 +流控;
第二种:直接点击流控规则下的 +新增流控规则
流控模式:
- 直接快速失败
直接失败的效果:
- 线程数:
比如a请求过来,处理很慢,在一直处理,此时b请求又过来了
此时因为a占用一个线程,此时要处理b请求就只有额外开启一个线程
那么就会报错
3. 关联:
应用场景: 比如支付接口达到阈值,就要限流下订单的接口,防止一直有订单
当testA达到阈值,qps大于1,就让testB之后的请求直接失败
可以使用postman压测:
-
访问testB
-
postman里新建多线程集合组
-
将访问地址添加进新线程组
-
当点击Run,再次点击testA,发现关联失败
-
链路:
多个请求调用同一个微服务 -
预热Warm up:
应用场景
-
排队等待:
4. 降级规则
就是熔断降级
1,RT配置:
新增一个请求方法用于测试,由于testD的时间延时1s完成,超过了设定RT阈值:200ms;并且jmeter压测是1秒10个请求,大于默认的QPS=5。这2个条件同时满足,触发熔断,断路器打开,微服务不可用。
配置RT:
这里配置的PT,默认是秒级的平均响应时间
默认计算平均时间是: 1秒类进入5个请求,并且响应的平均值超过阈值(这里的200ms),就报错]
1秒5请求是Sentinel默认设置的
测试
默认熔断后.就直接抛出异常
2,异常比例:
修改请求方法
配置:异常比例:只允许20%的错误且QPS>=5, 时间窗口1s内不能使用
如果没触发熔断,这正常抛出异常:
触发熔断:
3, 异常数:
@GetMapping("/testE")
public String testE() {
int age=10/0;
log.info("异常数。。。。。。。。。。。");
return "--------------testE异常数";
}
一分钟之内,有5个请求发送异常,进入熔断;
超过时间窗口70s后,则关闭断路器,再请求次数在异常数(5次)之内,会报错误界面
5. 热点规则
比如:
localhost:8080/aa?name=aa
localhost:8080/aa?name=b’b
加入两个请求中,带有参数aa的请求访问频次非常高,我们就现在name==aa的请求,但是bb的不限制
如何自定义降级方法,而不是默认的抛出异常?
使用@SentinelResource直接实现降级方法,它等同Hystrix的@HystrixCommand
定义热点规则:
此时我们访问/testHotkey并且带上才是p1
如果qps大于1,就会触发我们定义的降级方法
但是我们的参数是P2,就没有问题
只有带了p1,才可能会触发热点限流
2,设置热点规则中的其他选项:
需求:
测试
注意:
参数例外项:参数类型只支持,8种基本类型+String类
注意:
如果我们程序出现异常,是不会走blockHander的降级方法的,因为这个方法只配置了热点规则,没有配置限流规则
我们这里配置的降级方法是sentinel针对热点规则配置的
只有触发热点规则才会降级
6. 系统规则
系统自适应限流:
从整体维度对应用入口进行限流
对整体限流,比如设置qps到达100,这里限流会限制整个系统不可以
测试:
7. @SentinelResource注解:(blockHandler,fallback两大属性)
用于配置降级等功能
1,环境搭建
-
为8401添加依赖
添加我们自己的commone包的依赖
-
额外创建一个controller类
-
配置限流
注意,我们这里配置规则,资源名指定的是@SentinelResource注解value的值,
这样也是可以的,也就是不一定要指定访问路径
4. 测试.
可以看到已经进入降级方法了
5. 此时我们关闭8401服务
可以看到,这些定义的规则是临时的,关闭服务,规则就没有了
可以看到,上面配置的降级方法,又出现Hystrix遇到的问题了
降级方法与业务方法耦合
每个业务方法都需要对应一个降级方法
自定义限流处理逻辑:
-
单独创建一个类,用于处理限流
-
在controller中,指定使用自定义类中的方法作为降级方法
-
Sentinel中定义流控规则:
这里资源名,是以url指定,也可以使用@SentinelResource注解value的值指定
4. 测试:
- 整体:
@SentinelResource注解的其他属性:
8. 服务熔断:
-
启动nacos和sentinel
-
新建两个pay模块 9003和9004
-
pom
-
配置文件
-
-
主启动类
@SpringBootApplication @EnableDiscoveryClient public class PaymentMain9003 { public static void main(String[] args) { SpringApplication.run(PaymentMain9003.class,args); } }
-
controller
然后启动9003.9004
3.新建一个order-84消费者模块:
-
pom
与上面的pay一模一样
-
配置文件
-
主启动类
-
配置类
-
controller
-
为业务方法添加fallback来指定降级方法:(处理业务异常)
重启order
测试:
所以,fallback是用于管理异常的,当业务方法发生异常,可以降级到指定方法
注意,我们这里并没有使用sentinel配置任何规则,但是却降级成功,就是因为
fallback是用于管理异常的,当业务方法发生异常,可以降级到指定方法==
-
为业务方法添加blockHandler,看看是什么效果(处理Sentinel控制台配置违规)
重启84,访问业务方法:
可以看到.,直接报错了,并没有降级 也就是说,blockHandler只对sentienl定义的规则降级
-
如果fallback和blockHandler都配置呢?]
设置qps规则,阈值1
测试:
可以看到,当两个都同时生效时,blockhandler优先生效 -
@SentinelResource还有一个属性,exceptionsToIgnore
exceptionsToIgnore指定一个异常类,
表示如果当前方法抛出的是指定的异常,不降级,直接对用户抛出异常
9. sentinel整合ribbon+openFeign+fallback
-
修改84模块,使其支持feign
-
pom
-
配置文件
-
主启动类,也要修改
-
创建远程调用pay模块的接口
-
创建这个接口的实现类,用于降级
-
再次修改接口,指定降级类
-
controller添加远程调用
-
测试
启动9003,84 -
测试,如果关闭9003.看看84会不会降级
可以看到,正常降级了
-
熔断框架比较
10. sentinel持久化规则
默认规则是临时存储的,重启sentinel就会消失
这里以之前的8401为案例进行修改:
-
修改8401的pom
添加: <!-- SpringCloud ailibaba sentinel-datasource-nacos 持久化需要用到--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>
-
修改配置文件:
添加:
实际上就是指定,我们的规则要保证在哪个名称空间的哪个分组下这里没有指定namespace, 但是是可以指定的
注意,这里的dataid要与8401的服务名一致
-
在nacos中创建一个配置文件,dataId就是上面配置文件中指定的
json中,这些属性的含义:
-
启动8401:
可以看到,直接读取到了规则 -
关闭8401
-
此时重启8401,如果sentinel又可以正常读取到规则,那么证明持久化成功
可以看到,又重新出现了