1.缓存
1.1 增加HystrixRequestContextFilter
/**
* hystrix请求上下文过滤器
* @author Administrator
*
*/
public class HystrixRequestContextFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
chain.doFilter(request, response);
} catch (Exception e) {
e.printStackTrace();
} finally {
context.shutdown();
}
}
public void destroy() {
}
}
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(
new HystrixRequestContextFilter());
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
1.2 在command接口中增加getCacheKey
public class GetProductInfoCommand extends HystrixCommand<ProductInfo> {
...
@Override
protected String getCacheKey() {
return "product_info_" + productId;
}
...
}
1.2 手工清理缓存
public static class GetterCommand extends HystrixCommand<String> {
private static final HystrixCommandKey GETTER_KEY = HystrixCommandKey.Factory.asKey("GetterCommand");
private final int id;
public GetterCommand(int id) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetSetGet"))
.andCommandKey(GETTER_KEY));
this.id = id;
}
@Override
protected String run() {
return prefixStoredOnRemoteDataStore + id;
}
@Override
protected String getCacheKey() {
return String.valueOf(id);
}
/**
* Allow the cache to be flushed for this object.
*
* @param id
* argument that would normally be passed to the command
*/
public static void flushCache(int id) {
HystrixRequestCache.getInstance(GETTER_KEY,
HystrixConcurrencyStrategyDefault.getInstance()).clear(String.valueOf(id));
}
}
public static class SetterCommand extends HystrixCommand<Void> {
private final int id;
private final String prefix;
public SetterCommand(int id, String prefix) {
super(HystrixCommandGroupKey.Factory.asKey("GetSetGet"));
this.id = id;
this.prefix = prefix;
}
@Override
protected Void run() {
// persist the value against the datastore
prefixStoredOnRemoteDataStore = prefix;
// flush the cache
GetterCommand.flushCache(id);
// no return value
return null;
}
}
2.fallback降级机制
- hystrix调用各种接口,或者访问外部依赖,mysql,redis,zookeeper,kafka,等等,如果出现了任何异常的情况
- 对每个外部依赖,无论是服务接口,中间件,资源隔离,对外部依赖只能用一定量的资源去访问,线程池/信号量,如果资源池已满,reject
- 访问外部依赖的时候,访问时间过长,可能就会导致超时,报一个TimeoutException异常,timeout
- 对外部依赖的东西访问的时候出现了异常,发送异常事件到短路器中去进行统计,如果短路器发现异常事件的占比达到了一定的比例,直接开启短路,circuit breaker
2.1 配置
public class GetProductInfoCommand extends HystrixCommand<ProductInfo> {
...
@Override
protected ProductInfo getFallback() {
ProductInfo productInfo = new ProductInfo();
productInfo.setName("降级商品");
return productInfo;
}
...
}
//HystrixObservableCommand,是实现resumeWithFallback方法
2.2 线程池/队列/信号量满触发fallback
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(10)
.withMaxQueueSize(12)
.withQueueSizeRejectionThreshold(15))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withFallbackIsolationSemaphoreMaxConcurrentRequests(30)
3.短路器
-
如果经过短路器的流量超过了一定的阈值,HystrixCommandProperties.circuitBreakerRequestVolumeThreshold(20)
举个例子,可能看起来是这样子的,要求在10s内,经过短路器的流量必须达到20个;在10s内,经过短路器的流量才10个,那么根本不会去判断要不要短路 -
如果断路器统计到的异常调用的占比超过了一定的阈值,HystrixCommandProperties.circuitBreakerErrorThresholdPercentage(60)
如果达到了上面的要求,比如说在10s内,经过短路器的流量(你只要执行一个command,这个请求就一定会经过短路器),达到了30个;同时其中异常的访问数量,占到了一定的比例,比如说60%的请求都是异常(报错,timeout,reject),会开启短路 -
然后断路器从close状态转换到open状态
-
断路器打开的时候,所有经过该断路器的请求全部被短路,不调用后端服务,直接走fallback降级
-
经过了一段时间之后,HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds(5000),会half-open,让一条请求经过短路器,看能不能正常调用。如果调用成功了,那么就自动恢复,转到close状态
-
短路器,会自动恢复的,half-open,半开状态。断路器半开状态,Open状态过一段时间(默认5s)转为此状态来尝试恢复。此状态时:允许有且仅一个请求进入,一旦请求成功就关闭断路器。请求失败就到Open状态(这样再过5秒才能转到半开状态)
3.1 配置
-
circuitBreaker.enabled
HystrixCommandProperties.Setter() .withCircuitBreakerEnabled(boolean value)
控制短路器是否允许工作,包括跟踪依赖服务调用的健康状况,以及对异常情况过多时是否允许触发短路,默认是true
-
circuitBreaker.requestVolumeThreshold
HystrixCommandProperties.Setter() .withCircuitBreakerRequestVolumeThreshold(int value)
设置一个rolling window,滑动窗口中,最少要有多少个请求时,才触发开启短路。
举例来说,如果设置为20(默认值),那么在一个10秒的滑动窗口内,如果只有19个请求,即使这19个请求都是异常的,也是不会触发开启短路器的。
-
circuitBreaker.sleepWindowInMilliseconds
HystrixCommandProperties.Setter() .withCircuitBreakerSleepWindowInMilliseconds(int value)
设置在短路之后,需要在多长时间内直接reject请求,然后在这段时间之后,再重新到holf-open状态,尝试允许请求通过以及自动恢复,默认值是5000毫秒
-
circuitBreaker.errorThresholdPercentage
HystrixCommandProperties.Setter() .withCircuitBreakerErrorThresholdPercentage(int value)
设置异常请求量的百分比,当异常请求达到这个百分比时,就触发打开短路器,默认是50,也就是50%
-
circuitBreaker.forceOpen
HystrixCommandProperties.Setter() .withCircuitBreakerForceOpen(boolean value)
如果设置为true的话,直接强迫打开短路器,相当于是手动短路了,手动降级,默认false
-
circuitBreaker.forceClosed
HystrixCommandProperties.Setter() .withCircuitBreakerForceClosed(boolean value)
如果设置为ture的话,直接强迫关闭短路器,相当于是手动停止短路了,手动升级,默认false
4.超时
-
execution.isolation.thread.timeoutInMilliseconds
HystrixCommandProperties.Setter() .withExecutionTimeoutInMilliseconds(int value)
(1) 手动设置timeout时长,一个command运行超出这个时间,就被认为是timeout,然后将hystrix command标识为timeout,同时执行fallback降级逻辑。默认是1000,也就是1000毫秒。
(2) 特别要注意的是,这个时间要设置长一点,因为不仅仅要算接口实际执行的时长,还要计算在队列中到线程池中的时长。 -
execution.timeout.enabled
HystrixCommandProperties.Setter() .withExecutionTimeoutEnabled(boolean value)
控制是否要打开timeout机制,默认是true。