目录
1、概念
在分布式链路中,有一个服务宕机了就会整个业务线瘫痪。
熔断器,也叫断路器! (正常情况下断路器是关的只有出了问题才打开)用来保护微服务不雪崩的方法。
Hystrix是Netflix公司开源的一个项目,它提供了熔断器功能,能够阻止分布式系统中出现联动故障。Hystrix是通过隔离服务的访问点阻止联动故障的,并提供了故障的解决方案,从而提高了整个分布式系统的弹性。微博弹性云扩容Docker K8s。
2、创建项目
2.1 customer-server
参考:Spring Cloud OpenFeign快速入门_月融花下的博客-优快云博客
2.2 熔断器
2.2.1 添加依赖
<!--添加熔断的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.2.2 添加feign接口的实现类
2.2.3 指定熔断的类
2.2.4 开启熔断
2.2 rent-car-server
3、手写hystrix
3.1 创建项目
3.2 远程调用
3.2.1 RestTemplate接口
3.2.2 远程调用
3.3 熔断实现
3.3.1 熔断的状态
3.3.2 拦截面(切面aop)
3.3.2.1 aop依赖加入
3.3.2.2 书写注解
3.3.2.3 添加注解
3.3.2.4 切面(环绕通知)
3.3.2.5 断路器模型
package com.example.myfinish.model;
import lombok.Data;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 断路器的模型
*/
@Data
public class Finish {
/**
* 状态
*/
private FinishStatus status = FinishStatus.CLOSE;
/**
* 窗口时间
*/
public static final Integer WIND0W_TIME=20;
/**
* 最大失败次数
*/
public static final Integer MAX_FAIL_COUNT=3;
/**
* 当前断路器失败了几次
* AtomicInteger 可以保证线程安全
*/
private AtomicInteger currentFailCount = new AtomicInteger(0);
/**
* 线程池
*/
private ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
4,
8,
30,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(2000),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
{
poolExecutor.execute(()->{
//定时删除
while (true){
try {
TimeUnit.SECONDS.sleep(WIND0W_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.currentFailCount.set(0);
}
});
}
/**
* 记录失败次数
*/
public void addFailCount(){
int i = currentFailCount.incrementAndGet();
if (i>MAX_FAIL_COUNT){
//失败次数到了阈值,修改当前的状态为close
this.setStatus(FinishStatus.OPEN);
//当前断路器打开以后,就不能去访问了 需要变成半开
//等待一个时间窗口,让断路器变成半开
poolExecutor.execute(()->{
try {
TimeUnit.SECONDS.sleep(WIND0W_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setStatus(FinishStatus.HALF_OPEN);
//重置失败次数
this.currentFailCount.set(0);
});
}
}
}
3.3.2.6 切面逻辑
package com.example.myfinish.aspect;
import com.example.myfinish.model.Finish;
import com.example.myfinish.model.FinishStatus;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* 切面
*/
@Component
@Aspect //切面的注解
public class FinishAspect {
//一个消费者可以调用多个提供者,每个提供者都有自己的断路器
public static Map<String, Finish> finishMap = new HashMap<>();
static {
finishMap.put("order-server",new Finish());
}
//切点
//环绕通知 判断当前的状态
@Around(value = "@annotation(com.example.myfinish.anno.MyFinish)")
public Object firstAround(ProceedingJoinPoint joinPoint){
Object proceed = null;
//获取当前提供者的断路器
Finish finish = finishMap.get("order-server");
FinishStatus status = finish.getStatus();
Random random = new Random();
switch (status){
case OPEN:
//正常,去调用,执行目标方法
try {
proceed = joinPoint.proceed();
return proceed;
} catch (Throwable throwable) {
//调用失败 记录次数
finish.addFailCount();
throwable.printStackTrace();
}
case CLOSE:
//不能调用
return "我是备胎";
case HALF_OPEN:
//可以用少许流量去访问
int i = random.nextInt(5);
System.out.println(i);
if (i==1){
//去调用
try {
proceed = joinPoint.proceed();
//说明成功了
finish.setStatus(FinishStatus.CLOSE);
return proceed;
} catch (Throwable throwable) {
return "我是备胎";
}
}
default:
return "我是备胎";
}
}
}