一.熔断和降级的参考标准
(1)平均响应时间:
请求某个方法时,在某个时间段内,有N个请求的请求时间都超过了平均请求时间,那么在接下来的某个时间窗口内,对这个请求的调用将自动熔断
(2)异常比例
请求某个方法时,在某个时间段内,异常的数量超过了某个阈值,那么在接下来的某个时间窗口内,对这个请求的调用将自动熔断
二.Resilience4j的使用
1. 添加依赖
<!-- Resilience4j服务熔断和降级-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
2.修改接口的代码
(1)restTemplate
@GetMapping("/book")
public String getBook(){
String url = "http://bookservice/book/1";
// return restTemplate.getForObject(url+"/1",String.class);
//测试服务的熔断
return circuitBreakerFactory.create("testResilience4j").run(()->
restTemplate.getForObject(url,String.class),throwable -> "熔断该服务了!");
}
(2)Feign
@GetMapping("/slow")
public String testSlowResilience4j(){
return circuitBreakerFactory.create("slow").run(()->bookServiceClient
.getOneBookById(2),throwable -> "熔断返回值");
}
这里的“testRescilience4j”是熔断的ID
3.自定义熔断配置
(1)将熔断时间改为4S
//服务熔断和降级时间自定义配置
@Bean
public Customizer<Resilience4JCircuitBreakerFactory> defaultCustomizer(){
return factory->factory.configureDefault(id->new
Resilience4JConfigBuilder(id).timeLimiterConfig(TimeLimiterConfig.custom().
timeoutDuration(Duration.ofSeconds(4)).build())
.circuitBreakerConfig(CircuitBreakerConfig.ofDefaults()).build());
}
(2)个性化熔断策略
@Bean
public Customizer<Resilience4JCircuitBreakerFactory> slowCustomizer(){
return factory->factory.configure(builder->builder
.circuitBreakerConfig(CircuitBreakerConfig.ofDefaults())
.timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(1))
.build()),"slow");
}
"slow"就是该熔断的ID,当响应时间超过4s时触发熔断
三.限流
1.限流算法
(1)计数器(固定窗口)算法
在指定的时间周期内,累加访问的次数达到设定的阈值时,触发的限流策略,
实现方法: 可以使用Redis的incr原子自增,在结合key的过期时间实现
缺点: 会有一个临界问题
(2)滑动时间窗口算法
类似于TCP的滑动窗口,将时间周期分割为多个小的时间窗口,分别在每个小的时间窗口内记录访问次数,然后根据时间将窗口向前滑动并删除过期的小时间窗口,最终只需要统计滑动窗口范围内的小时间窗口的总的请求数即可。
(3)漏桶限流算法
维持一个漏斗,使其具有恒定的流出速度,不管水流入的速度有多快,出水的速度始终保持不变,类似消息中间件,不管消息的生产者请求量有多大,消息的处理能力取决于消费者
缺点: 当系统在短时间内有突发的大流量时,漏桶算法就处理不了了
(4)令牌桶限流算法
为了改进漏桶限流算法引入令牌,增加一个大小固定的容器,令牌桶,系统以恒定的速度向令牌桶中放入令牌,如果有客户端来请求,需要先从令牌桶中拿一个令牌,拿到了令牌才有资格访问系统,这时令牌桶中相应的少了一个令牌,当令牌桶满的时候,再向令牌桶生成令牌,令牌就会被抛弃。
四.Sentinel使用
1.使用步骤:
(1)定义资源
(2)定义规则
(3检验规则是否生效
2.Sentinel安装
官网:https://github.com/alibaba/Sentinel/releases
运行:
java -jar -Dserver.port=18080 sentinel-dashboard-1.8.1.jar
3.引入Sentinel依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<!-- <version>2021.1</version>-->
</dependency>
4.修改配置文件
spring:
application:
name: book-service
cloud:
nacos:
server-addr: localhost:8848
#限流
sentinel:
eager: true
transport:
dashboard: localhost:18080
5.编写接口测试
/**
* 测试sentinel流控
* @return
*/
@GetMapping("/sentinel")
public String testSentinel(){
return "successs!";
}
可以看到该接口成功返回结果
下面对该接口设置限流:
再次测试快速点击鼠标:
可以发现已经被限流了!
QPS: 请求在进入服务之前限制
线程数: 请求到达服务后,当服务线程处理不完时进行限制
6.Sentinel热点规则
设置热点规则:
修改代码:
public class CustomHandler {
public static String handleException1(BlockException e){
return "异常1";
}
public static String handleException2(BlockException e){
return "异常2";
}
}
@SentinelResource(value = "test-custom",blockHandlerClass = CustomHandler.class,
blockHandler = "handleException1")
@GetMapping("/{id}")
public Book getOneByid(@PathVariable("id")Integer id){
return bookService.getOneByid(id);
}
这样当服务触发限流时就会进入类CustomHandler中的handleExecption1方法处理