-
添加熔断依赖
1 <dependency> 2 <groupId>org.springframework.cloud</groupId> 3 <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> 4 </dependency> -
application.yml 配置熔断
1#------feign配置--------- 2feign: 3 client: 4 config: 5 default: 6 connectTimeout: 5000 #feign 远程连接超时时间 5s 7 readTimeout: 10000 #feign 远程获取数据超时时间 10s 8 loggerLevel: basic 9 hystrix: 10 enabled: true # 启用熔断 11#------------hystrix 熔断配置------------------- 12hystrix: 13 command: 14 default: 15 execution: 16 timeout: 17 enabled: true 18 isolation: 19 thread: 20 timeoutInMilliseconds: 20000 #超时多长时间,熔断 20s 21 22注意:1.通常熔断的超时时间需要配置的比ReadTimeout长,ReadTimeout比ConnectTimeout长,否则还未重试,就熔断了; 23 2.为了确保重试机制的正常运作,理论上(以实际情况为准)建议hystrix的超时时间为:(1 + MaxAutoRetries + MaxAutoRetriesNextServer) * ReadTimeout; -
开启熔断后,不能获取ThreadLocal 中的设置的值解决方法:
-
如:获取当前的 HttpServletRequest 为null
public static HttpServletRequest getRequest() { RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes(); return (requestAttributes == null) ? null : ((ServletRequestAttributes) requestAttributes).getRequest(); }
-
解决方法一:
1调整隔离策略: 2hystrix.command.default.execution.isolation.strategy: SEMAPHORE 3 4但该方案不是特别好。原因是Hystrix官方强烈建议使用THREAD作为隔离策略!
解决方法二: 自定义熔断的并发策略(可参考:https://www.jianshu.com/p/f30892335057):
1import com.netflix.hystrix.HystrixThreadPoolKey; 2import com.netflix.hystrix.HystrixThreadPoolProperties; 3import com.netflix.hystrix.strategy.HystrixPlugins; 4import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy; 5import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable; 6import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle; 7import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier; 8import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook; 9import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher; 10import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy; 11import com.netflix.hystrix.strategy.properties.HystrixProperty; 12import org.slf4j.Logger; 13import org.slf4j.LoggerFactory; 14import org.springframework.web.context.request.RequestAttributes; 15import org.springframework.web.context.request.RequestContextHolder; 16 17import java.util.concurrent.BlockingQueue; 18import java.util.concurrent.Callable; 19import java.util.concurrent.ThreadPoolExecutor; 20import java.util.concurrent.TimeUnit; 21 22/** 23 * 熔断并发策略 24 */ 25class FeignHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy { 26 private static final Logger log = LoggerFactory.getLogger(FeignHystrixConcurrencyStrategy.class); 27 private HystrixConcurrencyStrategy delegate; 28 29 public FeignHystrixConcurrencyStrategy() { 30 try { 31 this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy(); 32 if (this.delegate instanceof FeignHystrixConcurrencyStrategy) { 33 return; 34 } 35 HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance().getCommandExecutionHook(); 36 HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier(); 37 HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher(); 38 HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy(); 39 this.logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher, propertiesStrategy); 40 HystrixPlugins.reset(); 41 HystrixPlugins.getInstance().registerConcurrencyStrategy(this); 42 HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook); 43 HystrixPlugins.getInstance().registerEventNotifier(eventNotifier); 44 HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher); 45 HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy); 46 } catch (Exception var5) { 47 log.error("Failed to register Sleuth Hystrix Concurrency Strategy", var5); 48 } 49 50 } 51 52 private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier, HystrixMetricsPublisher metricsPublisher, HystrixPropertiesStrategy propertiesStrategy) { 53 if (log.isDebugEnabled()) { 54 log.debug("Current Hystrix plugins configuration is [concurrencyStrategy [" + this.delegate + "],eventNotifier [" + eventNotifier + "],metricPublisher [" + metricsPublisher + "],propertiesStrategy [" + propertiesStrategy + "],]"); 55 log.debug("Registering Sleuth Hystrix Concurrency Strategy."); 56 } 57 58 } 59 60 public <T> Callable<T> wrapCallable(Callable<T> callable) { 61 RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); 62 return new FeignHystrixConcurrencyStrategy.WrappedCallable(callable, requestAttributes); 63 } 64 65 public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixProperty<Integer> corePoolSize, HystrixProperty<Integer> maximumPoolSize, HystrixProperty<Integer> keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { 66 return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); 67 } 68 69 public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties threadPoolProperties) { 70 return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties); 71 } 72 73 public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) { 74 return this.delegate.getBlockingQueue(maxQueueSize); 75 } 76 77 public <T> HystrixRequestVariable<T> getRequestVariable(HystrixRequestVariableLifecycle<T> rv) { 78 return this.delegate.getRequestVariable(rv); 79 } 80 81 static class WrappedCallable<T> implements Callable<T> { 82 private final Callable<T> target; 83 private final RequestAttributes requestAttributes; 84 85 public WrappedCallable(Callable<T> target, RequestAttributes requestAttributes) { 86 this.target = target; 87 this.requestAttributes = requestAttributes; 88 } 89 90 public T call() throws Exception { 91 try { 92 RequestContextHolder.setRequestAttributes(this.requestAttributes); 93 return target.call(); 94 } finally { 95 RequestContextHolder.resetRequestAttributes(); 96 } 97 } 98 } 99}
Feign 请求微服务请求头添加Token:
1import com.weaf.onet.utils.WebUtil; 2import feign.RequestInterceptor; 3import feign.RequestTemplate; 4 5/** 6 * Feign请求拦截器(调用微服务层) 7 **/ 8 class FeignAuthRequestInterceptor implements RequestInterceptor { 9 10 @Override 11 public void apply(RequestTemplate template) { 12 Integer tenantId= WebUtil.getTenantId(); 13 template.header("tenantId", String.valueOf(tenantId)); 14 } 15 16}
配置 Feign :
1import org.springframework.context.annotation.Bean; 2import org.springframework.context.annotation.Configuration; 3 4 5@Configuration 6public class FeignConfiguration { 7 8 /** 9 * 创建Feign请求拦截器,在发送请求前设置认证的token,各个微服务将token设置到环境变量中来达到通用 10 * @return 11 */ 12 @Bean 13 public FeignAuthRequestInterceptor authRequestInterceptor() { 14 return new FeignAuthRequestInterceptor(); 15 } 16 17 // 配置熔断策略 18 @Bean 19 public FeignHystrixConcurrencyStrategy feignHystrixConcurrencyStrategy() { 20 return new FeignHystrixConcurrencyStrategy(); 21 } 22}