前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Feign拦截器熔断机制踩坑?

Feign拦截器熔断机制踩坑?

作者头像
技术从心
发布2021-01-18 12:22:13
1.7K0
发布2021-01-18 12:22:13
举报
文章被收录于专栏:技术从心技术从心

记一次fiegn拦截器传递token的一个坑,发生甚么事了?

事情是这样的,今天调试调用一个微服务的项目,但是发现在调用的过程中发现内部调用服务的时候 token 没有传递过去。

先看下yaml的配置:

代码语言:javascript
复制
feign:
  hystrix:
    enabled: true # 开启熔断
  client:
    config:
      default:
        connectTimeout: 100000
        readTimeout: 100000
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 30000
ribbon:
  ReadTimeout: 60000
  ConnectTimeout: 60000

关键在于开启熔断,此时feign接口熔断机制为:线程模式,熔断机制正常

使用RequestInterceptor拦截器

代码语言:javascript
复制
@Configuration
public class FeignConfiguration implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        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);
            }
        }
    }
    @Bean
    public Logger.Level config(){
        return Logger.Level.FULL;
    }
}

拦截没有啥问题,但是报错了,如下:

啪的一下很快就报错了哈,我都没反应过来

出现该错误原因:

在feign调用之前,我给他开启了一个拦截器 RequestInterceptor实现类 里面有使用到ServletRequestAttributes 获取请求数据

当feign开启熔断模式的时候,feign 调用会失败 (feign: hystrix: enabled: true)

原因:feign 使用的是线程池模式,当开启熔断的时候,feign 所在的服务端不在同一个线程,这时attributes取到的将会是空值

内部应用大致是 Thread 的线程,开启熔断以后请求的线程发生了变化,导致线程不一致了,所以 token 也没有传递过去。

解决方案:

将hystrix熔断方式:线程模式改为信号量模式

代码语言:javascript
复制
feign:
  hystrix:
    enabled: true
  client:
    config:
      default:
        connectTimeout: 100000
        readTimeout: 100000
hystrix:
 command:
   default:
     execution:
       isolation:
         thread:
           timeoutInMilliseconds: 30000
         strategy: SEMAPHORE  
ribbon:
  ReadTimeout: 60000
  ConnectTimeout: 60000

关键所在: strategy: SEMAPHORE

可以修改默认隔离策略为信号量模式:

加上线程信号量即可完美的解决,但是官方并不推荐这么使用。

推荐使用:

自定义策略

HystrixConcurrencyStrategy 是提供给开发者去自定义hystrix内部线程池及其队列,还提供了包装callable的方法,以及传递上下文变量的方法。

所以可以继承了HystrixConcurrencyStrategy,用来实现了自己的并发策略。

代码语言:javascript
复制
@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);

参考链接 https://segmentfault.com/a/1190000021060393

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-01-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 技术从心 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用RequestInterceptor拦截器
  • 出现该错误原因:
  • 解决方案:
  • 推荐使用:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档