添加熔断依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
application.yml 配置熔断
#------feign配置--------- feign: client: config: default: connectTimeout: 5000 #feign 远程连接超时时间 5s readTimeout: 10000 #feign 远程获取数据超时时间 10s loggerLevel: basic hystrix: enabled: true # 启用熔断 #------------hystrix 熔断配置------------------- hystrix: command: default: execution: timeout: enabled: true isolation: thread: timeoutInMilliseconds: 20000 #超时多长时间,熔断 20s 注意:1.通常熔断的超时时间需要配置的比ReadTimeout长,ReadTimeout比ConnectTimeout长,否则还未重试,就熔断了; 2.为了确保重试机制的正常运作,理论上(以实际情况为准)建议hystrix的超时时间为:(1 + MaxAutoRetries + MaxAutoRetriesNextServer) * ReadTimeout;
开启熔断后,不能获取ThreadLocal 中的设置的值解决方法:
如:获取当前的 HttpServletRequest 为null
public static HttpServletRequest getRequest() { RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes(); return (requestAttributes == null) ? null : ((ServletRequestAttributes) requestAttributes).getRequest(); }
解决方法一:
调整隔离策略:
hystrix.command.default.execution.isolation.strategy: SEMAPHORE
但该方案不是特别好。原因是Hystrix官方强烈建议使用THREAD作为隔离策略!
解决方法二: 自定义熔断的并发策略(可参考:https://www.jianshu.com/p/f30892335057):
import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import com.netflix.hystrix.strategy.properties.HystrixProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 熔断并发策略
*/
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) {
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.getInstance().registerConcurrencyStrategy(this);
HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
} catch (Exception var5) {
log.error("Failed to register Sleuth Hystrix Concurrency Strategy", var5);
}
}
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.");
}
}
public <T> Callable<T> wrapCallable(Callable<T> callable) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
return new FeignHystrixConcurrencyStrategy.WrappedCallable(callable, requestAttributes);
}
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);
}
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties threadPoolProperties) {
return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties);
}
public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
return this.delegate.getBlockingQueue(maxQueueSize);
}
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;
public WrappedCallable(Callable<T> target, RequestAttributes requestAttributes) {
this.target = target;
this.requestAttributes = requestAttributes;
}
public T call() throws Exception {
try {
RequestContextHolder.setRequestAttributes(this.requestAttributes);
return target.call();
} finally {
RequestContextHolder.resetRequestAttributes();
}
}
}
}
Feign 请求微服务请求头添加Token:
import com.weaf.onet.utils.WebUtil;
import feign.RequestInterceptor;
import feign.RequestTemplate;
/**
* Feign请求拦截器(调用微服务层)
**/
class FeignAuthRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
Integer tenantId= WebUtil.getTenantId();
template.header("tenantId", String.valueOf(tenantId));
}
}
配置 Feign :
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfiguration {
/**
* 创建Feign请求拦截器,在发送请求前设置认证的token,各个微服务将token设置到环境变量中来达到通用
* @return
*/
@Bean
public FeignAuthRequestInterceptor authRequestInterceptor() {
return new FeignAuthRequestInterceptor();
}
// 配置熔断策略
@Bean
public FeignHystrixConcurrencyStrategy feignHystrixConcurrencyStrategy() {
return new FeignHystrixConcurrencyStrategy();
}
}