1.引入的hystrix的starter启动会根据根据spring.factories的读取配置类HystrixCircuitBreakerConfiguration
2.该配置类会实例化几个bean,重要的是一个切面
3.这个切面的切入点就是@HystrixCommand注解的方法,执行有@HystrixCommand的方法会先执行circuitBearker的方法判断断路器是否打开,是否允许正常执行请求,标记断路器执行当前请求后的状态。如下源码断路器接口中第二个静态内部类就是断路器三个核心方法的实现。成员变量有如下几个:
private final HystrixCommandProperties properties;-----保存熔断器相关配置属性
private final HystrixCommandMetrics metrics;---------收集时间窗口内的熔断器指标,这些指标可以通过端点/actuator/hystrix.stream暴露, 详见https://mp.csdn.net/postedit/88908716
private AtomicBoolean circuitOpen = new AtomicBoolean(false);-----------保存熔断器当前状态,并原子类保证多线程安全
private AtomicLong circuitOpenedOrLastTestedTime = new AtomicLong();-----------断路器打开或上次检测时间,也是原子类
public interface HystrixCircuitBreaker {
boolean allowRequest();
boolean isOpen();
void markSuccess();
public static class NoOpCircuitBreaker implements HystrixCircuitBreaker {
public NoOpCircuitBreaker() {
}
public boolean allowRequest() {
return true;
}
public boolean isOpen() {
return false;
}
public void markSuccess() {
}
}
public static class HystrixCircuitBreakerImpl implements HystrixCircuitBreaker {
private final HystrixCommandProperties properties;
private final HystrixCommandMetrics metrics;
private AtomicBoolean circuitOpen = new AtomicBoolean(false);
private AtomicLong circuitOpenedOrLastTestedTime = new AtomicLong();
protected HystrixCircuitBreakerImpl(HystrixCommandKey key, HystrixCommandGroupKey commandGroup, HystrixCommandProperties properties, HystrixCommandMetrics metrics) {
this.properties = properties;
this.metrics = metrics;
}
public void markSuccess() {
if (this.circuitOpen.get() && this.circuitOpen.compareAndSet(true, false)) {
this.metrics.resetStream();
}
}
public boolean allowRequest() {
if ((Boolean)this.properties.circuitBreakerForceOpen().get()) {
return false;
} else if ((Boolean)this.properties.circuitBreakerForceClosed().get()) {
this.isOpen();
return true;
} else {
return !this.isOpen() || this.allowSingleTest();
}
}
public boolean allowSingleTest() {
long timeCircuitOpenedOrWasLastTested = this.circuitOpenedOrLastTestedTime.get();
return this.circuitOpen.get() && System.currentTimeMillis() > timeCircuitOpenedOrWasLastTested + (long)(Integer)this.properties.circuitBreakerSleepWindowInMilliseconds().get() && this.circuitOpenedOrLastTestedTime.compareAndSet(timeCircuitOpenedOrWasLastTested, System.currentTimeMillis());
}
public boolean isOpen() {
if (this.circuitOpen.get()) {
return true;
} else {
HealthCounts health = this.metrics.getHealthCounts();
if (health.getTotalRequests() < (long)(Integer)this.properties.circuitBreakerRequestVolumeThreshold().get()) {
return false;
} else if (health.getErrorPercentage() < (Integer)this.properties.circuitBreakerErrorThresholdPercentage().get()) {
return false;
} else if (this.circuitOpen.compareAndSet(false, true)) {
this.circuitOpenedOrLastTestedTime.set(System.currentTimeMillis());
return true;
} else {
return true;
}
}
}
}
public static class Factory {
private static ConcurrentHashMap<String, HystrixCircuitBreaker> circuitBreakersByCommand = new ConcurrentHashMap();
public Factory() {
}
public static HystrixCircuitBreaker getInstance(HystrixCommandKey key, HystrixCommandGroupKey group, HystrixCommandProperties properties, HystrixCommandMetrics metrics) {
HystrixCircuitBreaker previouslyCached = (HystrixCircuitBreaker)circuitBreakersByCommand.get(key.name());
if (previouslyCached != null) {
return previouslyCached;
} else {
HystrixCircuitBreaker cbForCommand = (HystrixCircuitBreaker)circuitBreakersByCommand.putIfAbsent(key.name(), new HystrixCircuitBreaker.HystrixCircuitBreakerImpl(key, group, properties, metrics));
return cbForCommand == null ? (HystrixCircuitBreaker)circuitBreakersByCommand.get(key.name()) : cbForCommand;
}
}
public static HystrixCircuitBreaker getInstance(HystrixCommandKey key) {
return (HystrixCircuitBreaker)circuitBreakersByCommand.get(key.name());
}
static void reset() {
circuitBreakersByCommand.clear();
}
}
}
备注:需要降级方法才走降级方法,进入降级方法会隐藏掉服务调用出错或超时日志不便于系统维护,且增加开发量
4.核心逻辑描述
构建Hystrix的Command对象, 调用执行方法.
Hystrix检查当前服务的熔断器开关是否开启, 若开启, 则执行降级服务getFallback方法.
若熔断器开关关闭, 则Hystrix检查当前服务的线程池是否能接收新的请求, 若超过线程池已满, 则执行降级服务getFallback方法.
若线程池接受请求, 则Hystrix开始执行服务调用具体逻辑run方法.
若服务执行失败, 则执行降级服务getFallback方法, 并将执行结果上报Metrics更新服务健康状况.
若服务执行超时, 则执行降级服务getFallback方法, 并将执行结果上报Metrics更新服务健康状况.
若服务执行成功, 返回正常结果.
若服务降级方法getFallback执行成功, 则返回降级结果.
若服务降级方法getFallback执行失败, 则抛出异常.
5.配置文件@seehttps://github.com/Netflix/Hystrix/wiki/Configuration,https://blog.csdn.net/u012314558/article/details/78347219
配置举例(IDEA没有提示滴)
#--------------主配置进行全局配置---------------------
#熔断超时时间
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=1000
#熔断阈值
hystrix.command.default.circuitBreaker.errorThresholdPercentage=50
#时间窗口,时间窗口内的 metrics指标会放到rollingStatisticalWindowBuckets滚动窗口统计桶中
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=10
#滚动窗口统计桶个数,即每秒的metrics指标放入一个桶,dashboard看到的监控指标每秒一变化
hystrix.command.default.circuitBreaker.rollingStatisticalWindowBuckets=10
#熔断器的核心线程池数
hystrix.threadpool.default.coreSize=16
#最大线程池数,需要配合allowMaximumSizeToDivergeFromCoreSize才生效
hystrix.threadpool.default.maximumSize=32
hystrix.threadpool.default.allowMaximumSizeToDivergeFromCoreSize=true
#最大任务队列和最大任务队列拒绝阈值
hystrix.threadpool.default.maxQueueSize=5
hystrix.threadpool.default.queueSizeRejectionThreshold=4
#--------------个别接口@HystrixCommand注解属性覆盖全局配置---------------------
@RequestMapping("/info/{userId}")
@HystrixCommand(fallbackMethod = "getOrderInfoERR" ,
commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000"),
@HystrixProperty(name = "execution.timeout.enabled", value = "false")})
public String getOrderInfo(@PathVariable("userId")String userId) {
System.out.println(LocalDateTime.now().toString());
return orderService.getOrderList(userId);
}