spring cloud -Finchley.SR2 feign 熔断配置 及 Hystrix传播ThreadLocal对象 解决方法

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

  • 添加熔断依赖
	 
	   org.springframework.cloud
	   spring-cloud-starter-netflix-hystrix
	 
  • 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  Callable wrapCallable(Callable callable) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        return new FeignHystrixConcurrencyStrategy.WrappedCallable(callable, requestAttributes);
    }

    public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixProperty corePoolSize, HystrixProperty maximumPoolSize, HystrixProperty keepAliveTime, TimeUnit unit, BlockingQueue 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 getBlockingQueue(int maxQueueSize) {
        return this.delegate.getBlockingQueue(maxQueueSize);
    }

    public  HystrixRequestVariable getRequestVariable(HystrixRequestVariableLifecycle rv) {
        return this.delegate.getRequestVariable(rv);
    }

    static class WrappedCallable implements Callable {
        private final Callable target;
        private final RequestAttributes requestAttributes;

        public WrappedCallable(Callable 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();
    }
}

 

转载于:https://my.oschina.net/haopeng/blog/3032550

你可能感兴趣的:(spring cloud -Finchley.SR2 feign 熔断配置 及 Hystrix传播ThreadLocal对象 解决方法)