開了hystrix 通過feign調不通服務的一次故障分析
一,微服務之間通過feign調用,本來都是正常走通的。在配置了hystrix 之後 就走不通了,只是有了個空指針異常
二,通過各種方式的查找,終於發現了問題的地方,代碼如下:
/**
* Feign配置
* 使用FeignClient進行服務間調用,傳遞headers信息
*/
@Configuration
public class FeignConfig implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = null;
if(RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes){
attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
}
if(attributes != null){
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
requestTemplate.header(name, values);
}
}
}
}
}
現在的代碼,我已經做了判空的判斷。不過,這樣也是不合理的。正常情況不可能爲空,爲什麼會空指針異常?
三,又經過各種查找,百度,google。終於找到問題所在,配置代碼如下:
#開啓hystrix
feign:
hystrix:
enabled: true
#配置hystrix超時
hystrix:
command:
default: #default全局有效,service id指定應用有效
execution:
timeout:
enabled: true
isolation:
thread:
timeoutInMilliseconds: 6000 #斷路器超時時間,默認1000ms
strategy: SEMAPHORE
#配置ribbon超時
ribbon:
OkToRetryOnAllOperations: false #對所有操作請求都進行重試,默認false
ReadTimeout: 10000 #負載均衡超時時間,默認值5000 要比hystrix超時大 否則 觸發不了熔斷
ConnectTimeout: 3000 #ribbon請求連接的超時時間,默認值2000
MaxAutoRetries: 0 #對當前實例的重試次數,默認0
MaxAutoRetriesNextServer: 1 #對切換實例的重試次數,默認1
我配置了hystrix,策略是thread,而獲取就不是同一個thread,所以出現了null。現在startegy被改成了SEMAPHORE,就暫時解決了這個問題。
四,官方不建議用SEMAPHORE這種隔離級別
可以自定義隔離級別 在繼承官方隔離基礎上,可以傳遞threadlocal
/**
* 修改默認的hystrix隔離策略 使得可以傳遞content
* @author liyouqing
*/
@Component
public class FeignHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
private static final Logger log = LoggerFactory.getLogger(FeignHystrixConcurrencyStrategy.class);
private HystrixConcurrencyStrategy delegate;
public FeignHystrixConcurrencyStrategy() {
try {
this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
if (this.delegate instanceof FeignHystrixConcurrencyStrategy) {
// Welcome to singleton hell...
return;
}
HystrixCommandExecutionHook commandExecutionHook =
HystrixPlugins.getInstance().getCommandExecutionHook();
HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
HystrixPropertiesStrategy propertiesStrategy =
HystrixPlugins.getInstance().getPropertiesStrategy();
this.logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher, propertiesStrategy);
HystrixPlugins.reset();
HystrixPlugins instance = HystrixPlugins.getInstance();
instance.registerConcurrencyStrategy(this);
instance.registerCommandExecutionHook(commandExecutionHook);
instance.registerEventNotifier(eventNotifier);
instance.registerMetricsPublisher(metricsPublisher);
instance.registerPropertiesStrategy(propertiesStrategy);
} catch (Exception e) {
log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e);
}
}
private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier,
HystrixMetricsPublisher metricsPublisher,
HystrixPropertiesStrategy propertiesStrategy) {
if (log.isDebugEnabled()) {
log.debug("Current Hystrix plugins configuration is [" + "concurrencyStrategy ["
+ this.delegate + "]," + "eventNotifier [" + eventNotifier + "]," + "metricPublisher ["
+ metricsPublisher + "]," + "propertiesStrategy [" + propertiesStrategy + "]," + "]");
log.debug("Registering Sleuth Hystrix Concurrency Strategy.");
}
}
@Override
public <T> Callable<T> wrapCallable(Callable<T> callable) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
return new WrappedCallable<>(callable, requestAttributes);
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
HystrixProperty<Integer> corePoolSize,
HystrixProperty<Integer> maximumPoolSize,
HystrixProperty<Integer> keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue) {
return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime,
unit, workQueue);
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
HystrixThreadPoolProperties threadPoolProperties) {
return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties);
}
@Override
public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
return this.delegate.getBlockingQueue(maxQueueSize);
}
@Override
public <T> HystrixRequestVariable<T> getRequestVariable(HystrixRequestVariableLifecycle<T> rv) {
return this.delegate.getRequestVariable(rv);
}
static class WrappedCallable<T> implements Callable<T> {
private final Callable<T> target;
private final RequestAttributes requestAttributes;
WrappedCallable(Callable<T> target, RequestAttributes requestAttributes) {
this.target = target;
this.requestAttributes = requestAttributes;
}
@Override
public T call() throws Exception {
try {
RequestContextHolder.setRequestAttributes(requestAttributes);
return target.call();
} finally {
RequestContextHolder.resetRequestAttributes();
}
}
}
}