主函数入口
增加启动注解
@EnableCircuitBreaker
服务接口
/**
* @Author: EzerbelCN
* @Date: 2020/7/23 10:32
*/
public interface PaymentService {
public String paymentInfo_OK(Integer id);
public String paymentInfo_Timeout(Integer id);
public String paymentCircuitBreaker(Integer id);
public String paymentCircuitBeaker_fallback(Integer id);
}
服务实现
/**
* @Author: EzerbelCN
* @Date: 2020/7/23 10:32
*/
@Service
public class PaymenServiceImpl implements PaymentService {
@Override
public String paymentInfo_OK(Integer id) {
return "线程池:"+Thread.currentThread().getName()+ " paymentInfo_OK, id: " + id + "\t" + "o(∩_∩)o 哈哈~";
}
//指定该执行超时时间为3秒钟
@HystrixCommand(fallbackMethod = "paymentInfo_Timeout_Handler",commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="5000")
})
@Override
public String paymentInfo_Timeout(Integer id) {
int res = 10/0;
int timeVal = 3;
try{TimeUnit.MILLISECONDS.sleep((timeVal * 1000));} catch(InterruptedException e){ e.printStackTrace(); }
//try{TimeUnit.SECONDS.sleep(timeVal);} catch(InterruptedException e){ e.printStackTrace(); }
return "线程池:"+Thread.currentThread().getName()+ " paymentInfo_Timeout, id: " + id + "\t" + "o(∩_∩)o 哈哈~ 耗时"+timeVal+"秒";
}
//一旦调用服务方法失败抛出错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法
public String paymentInfo_Timeout_Handler(Integer id){
return "线程池:"+Thread.currentThread().getName()+ " paymentInfo_Timeout,系统繁忙或运行出错,请稍后再试, id: " + id + "\t" + "~(>_<)~";
}
@HystrixCommand(fallbackMethod = "paymentCircuitBeaker_fallback",commandProperties = {
@HystrixProperty(name="circuitBreaker.enabled",value="true"),
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value="10"),
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value="10000"),
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value="60")
})
@Override
public String paymentCircuitBreaker(Integer id) {
if(id<0){
throw new RuntimeException(" exception ---------------> id can not be negative ( id 不能为负数) !");
}
String serialNumber = IdUtil.simpleUUID();
return Thread.currentThread().getName() + "\t" + "调用成功,流水号: " + serialNumber;
}
@Override
public String paymentCircuitBeaker_fallback(Integer id) {
return "id 不能为负数 , 请稍后再试 ┭┮﹏┭┮ id: " + id;
}
}
测试
多次错误后(id为负数),满足熔断条件:
- 窗口期10秒内,
- 请求次数至少10次,
- 错误率60%以及以上!
一旦熔断,则再次提供正数id时,不会立即通过。
而是等到窗口期内正确率上升到可接受范围才会从halfOpen转为close
附:可配置属性
protected HystrixCommandProperties(HystrixCommandKey key, HystrixCommandProperties.Setter builder, String propertyPrefix) {
this.key = key;
this.circuitBreakerEnabled = getProperty(propertyPrefix, key, "circuitBreaker.enabled", builder.getCircuitBreakerEnabled(), default_circuitBreakerEnabled);
this.circuitBreakerRequestVolumeThreshold = getProperty(propertyPrefix, key, "circuitBreaker.requestVolumeThreshold", builder.getCircuitBreakerRequestVolumeThreshold(), default_circuitBreakerRequestVolumeThreshold);
this.circuitBreakerSleepWindowInMilliseconds = getProperty(propertyPrefix, key, "circuitBreaker.sleepWindowInMilliseconds", builder.getCircuitBreakerSleepWindowInMilliseconds(), default_circuitBreakerSleepWindowInMilliseconds);
this.circuitBreakerErrorThresholdPercentage = getProperty(propertyPrefix, key, "circuitBreaker.errorThresholdPercentage", builder.getCircuitBreakerErrorThresholdPercentage(), default_circuitBreakerErrorThresholdPercentage);
this.circuitBreakerForceOpen = getProperty(propertyPrefix, key, "circuitBreaker.forceOpen", builder.getCircuitBreakerForceOpen(), default_circuitBreakerForceOpen);
this.circuitBreakerForceClosed = getProperty(propertyPrefix, key, "circuitBreaker.forceClosed", builder.getCircuitBreakerForceClosed(), default_circuitBreakerForceClosed);
this.executionIsolationStrategy = getProperty(propertyPrefix, key, "execution.isolation.strategy", builder.getExecutionIsolationStrategy(), default_executionIsolationStrategy);
//this property name is now misleading. //TODO figure out a good way to deprecate this property name
this.executionTimeoutInMilliseconds = getProperty(propertyPrefix, key, "execution.isolation.thread.timeoutInMilliseconds", builder.getExecutionIsolationThreadTimeoutInMilliseconds(), default_executionTimeoutInMilliseconds);
this.executionTimeoutEnabled = getProperty(propertyPrefix, key, "execution.timeout.enabled", builder.getExecutionTimeoutEnabled(), default_executionTimeoutEnabled);
this.executionIsolationThreadInterruptOnTimeout = getProperty(propertyPrefix, key, "execution.isolation.thread.interruptOnTimeout", builder.getExecutionIsolationThreadInterruptOnTimeout(), default_executionIsolationThreadInterruptOnTimeout);
this.executionIsolationThreadInterruptOnFutureCancel = getProperty(propertyPrefix, key, "execution.isolation.thread.interruptOnFutureCancel", builder.getExecutionIsolationThreadInterruptOnFutureCancel(), default_executionIsolationThreadInterruptOnFutureCancel);
this.executionIsolationSemaphoreMaxConcurrentRequests = getProperty(propertyPrefix, key, "execution.isolation.semaphore.maxConcurrentRequests", builder.getExecutionIsolationSemaphoreMaxConcurrentRequests(), default_executionIsolationSemaphoreMaxConcurrentRequests);
this.fallbackIsolationSemaphoreMaxConcurrentRequests = getProperty(propertyPrefix, key, "fallback.isolation.semaphore.maxConcurrentRequests", builder.getFallbackIsolationSemaphoreMaxConcurrentRequests(), default_fallbackIsolationSemaphoreMaxConcurrentRequests);
this.fallbackEnabled = getProperty(propertyPrefix, key, "fallback.enabled", builder.getFallbackEnabled(), default_fallbackEnabled);
this.metricsRollingStatisticalWindowInMilliseconds = getProperty(propertyPrefix, key, "metrics.rollingStats.timeInMilliseconds", builder.getMetricsRollingStatisticalWindowInMilliseconds(), default_metricsRollingStatisticalWindow);
this.metricsRollingStatisticalWindowBuckets = getProperty(propertyPrefix, key, "metrics.rollingStats.numBuckets", builder.getMetricsRollingStatisticalWindowBuckets(), default_metricsRollingStatisticalWindowBuckets);
this.metricsRollingPercentileEnabled = getProperty(propertyPrefix, key, "metrics.rollingPercentile.enabled", builder.getMetricsRollingPercentileEnabled(), default_metricsRollingPercentileEnabled);
this.metricsRollingPercentileWindowInMilliseconds = getProperty(propertyPrefix, key, "metrics.rollingPercentile.timeInMilliseconds", builder.getMetricsRollingPercentileWindowInMilliseconds(), default_metricsRollingPercentileWindow);
this.metricsRollingPercentileWindowBuckets = getProperty(propertyPrefix, key, "metrics.rollingPercentile.numBuckets", builder.getMetricsRollingPercentileWindowBuckets(), default_metricsRollingPercentileWindowBuckets);
this.metricsRollingPercentileBucketSize = getProperty(propertyPrefix, key, "metrics.rollingPercentile.bucketSize", builder.getMetricsRollingPercentileBucketSize(), default_metricsRollingPercentileBucketSize);
this.metricsHealthSnapshotIntervalInMilliseconds = getProperty(propertyPrefix, key, "metrics.healthSnapshot.intervalInMilliseconds", builder.getMetricsHealthSnapshotIntervalInMilliseconds(), default_metricsHealthSnapshotIntervalInMilliseconds);
this.requestCacheEnabled = getProperty(propertyPrefix, key, "requestCache.enabled", builder.getRequestCacheEnabled(), default_requestCacheEnabled);
this.requestLogEnabled = getProperty(propertyPrefix, key, "requestLog.enabled", builder.getRequestLogEnabled(), default_requestLogEnabled);
// threadpool doesn't have a global override, only instance level makes sense
this.executionIsolationThreadPoolKeyOverride = forString().add(propertyPrefix + ".command." + key.name() + ".threadPoolKeyOverride", null).build();
}