本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Hystrix的短路器执行原理
HystrixCommandProperties.withExecutionTimeoutInMilliseconds():设置单位时间,判断HystrixCommandProperties.circuitBreakerRequestVolumeThreshold()的时间单位,默认10秒。单位毫秒。
HystrixCommandProperties.circuitBreakerRequestVolumeThreshold():单位时间内(默认10s内),请求超时数超出则触发熔断策略。默认值为20次请求数。
HystrixCommandProperties.circuitBreakerErrorThresholdPercentage():单位时间内,出现错误的请求百分比达到限制,则触发熔断策略。默认为50%。
HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds():当熔断策略开启后,延迟多久尝试再次请求远程服务。默认为5秒。单位毫秒。这5秒直接执行fallback方法,不在请求远程application service。
- 经过短路器的流量超过一定的阈值,HystrixCommandProperties.circuitBreakerRequestVolumeThreshold(20)
要求在10s内,经过短路器的流量必须达到20个;在10s内,经过短路器的流量才10个,不会去判断要不要短路
- 断路器统计的异常调用占比超过一定的阈值,HystrixCommandProperties.circuitBreakerErrorThresholdPercentage()
在10s内,经过短路器的流量,达到了30个;同时其中异常的访问数量,占到了一定的比例,比如说60%的请求都是异常(error,reject,timeout),会开启短路
-
断路器从close状态转换到open状态
-
断路器打开时,所有经过该断路器的请求全部被短路,不调用后端服务,直接走fallback降级
-
经过了一段时间之后,HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds(),会half-open,让一条请求经过短路器。如果调用成功了,那么就自动恢复,转到close状态
短路器的配置
circuitBreaker.enabled:控制短路器是否允许工作,包括跟踪依赖服务调用的健康状况,以及对异常情况过多时是否允许触发短路,默认是true
circuitBreaker.requestVolumeThreshold:设置一个rolling window滑动窗口,最少要有多少个请求时,才触发开启短路
circuitBreaker.sleepWindowInMilliseconds:设置在短路之后,需要在多长时间内直接reject请求,然后在这段时间之后,再重新设置为half-open状态,尝试允许请求通过以及自动恢复,默认值是5000毫秒
circuitBreaker.errorThresholdPercentage:设置异常请求量的百分比,当异常请求达到这个百分比时,就触发打开短路器,默认是50,也就是50%
circuitBreaker.forceOpen:如果设置为true的话,直接强迫打开短路器,相当于是手动短路,手动降级,默认false
circuitBreaker.forceClosed:如果设置为ture的话,直接强迫关闭短路器,相当于是手动停止短路,手动升级,默认false
package center.leon.eurekaconsumerribbonfeignapiimplhystrix.zoo.command;
import com.netflix.hystrix.*;
import lombok.extern.slf4j.Slf4j;
/**
* @author : Leon on XXM Mac
* @since : create in 2022/7/20 12:18 PM
*/
@Slf4j
public class MonkeyGetByIdOccurExceptionCommand extends HystrixCommand<String> {
private Long id;
public MonkeyGetByIdOccurExceptionCommand(Long id) {
super(Setter
.withGroupKey(
HystrixCommandGroupKey.Factory.asKey(MonkeyGetByIdOccurExceptionCommand.class.getSimpleName())
)
.andCommandPropertiesDefaults(
HystrixCommandProperties.Setter()
// 开启断路器
// 10秒内至少通过10个流量,失败占比10%时开启。10秒内通过10个,1个失败。
// 0-8 success, 9 error
// open circuit breaker
// sleep window 10秒 stt, circuit close
// 10-19 getFallback (actual 10-19 already recover)
// sleep window 10秒 end, circuit close
// 20-29 success
.withCircuitBreakerEnabled(true)
.withExecutionTimeoutInMilliseconds(10)
.withCircuitBreakerRequestVolumeThreshold(10)
.withCircuitBreakerErrorThresholdPercentage(10)
.withCircuitBreakerSleepWindowInMilliseconds(10 * 1000)
)
);
this.id = id;
}
@Override
protected String run() throws Exception {
if (id <= 0) {
throw new UnsupportedOperationException("ID不支持");
}
return "run " + MonkeyGetByIdOccurExceptionCommand.class.getSimpleName();
}
@Override
protected String getFallback() {
return "getFallback " + MonkeyGetByIdOccurExceptionCommand.class.getSimpleName();
}
}
package center.leon.eurekaconsumerribbonfeignapiimplhystrix;
import center.leon.common.web.response.RestResponse;
import center.leon.eurekaconsumerribbonfeignapiimplhystrix.cache.controller.CacheController;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.concurrent.ExecutionException;
/**
* @author Leon
*/
@Slf4j
@SpringBootApplication
public class EurekaConsumerRibbonFeignApiImplHystrixApplication {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ConfigurableApplicationContext run =
SpringApplication.run(EurekaConsumerRibbonFeignApiImplHystrixApplication.class,
args);
CacheController cacheController = run.getBean(CacheController.class);
RestResponse restResponse = null;
// 开启断路器
// 10秒内至少通过10个流量,失败占比10%时开启。10秒内通过10个,1个失败。
// 0-8 success, 9 error
// open circuit breaker
// sleep window 10秒 stt, circuit close
// 10-19 getFallback (actual 10-19 already recover)
// sleep window 10秒 end, circuit close
// 20-29 success
for (int i = 0; i < 100; i++) {
if (i < 9) {
restResponse = cacheController.cacheZooByIdOccurException(1L);
} else if (i < 10) {
restResponse = cacheController.cacheZooByIdOccurException(-1L);
} else if (i < 20) {
restResponse = cacheController.cacheZooByIdOccurException(1L);
} else if (i < 30) {
restResponse = cacheController.cacheZooByIdOccurException(1L);
} else {
restResponse = cacheController.cacheZooByIdOccurException(1L);
}
log.info("restResponse : {} - {}", i, restResponse.getData());
Thread.sleep(1000);
}
}
}