美文网首页
Feign自定义header无法传递

Feign自定义header无法传递

作者: 麦麦的生鱼片 | 来源:发表于2018-10-31 20:54 被阅读0次

    问题描述

    SpringCloud接入了Zipkin, 并使用header字段tid做为系统全局的traceId. 在入口中的tid已经被设置, 并放入MDC中, 但是在被调方无法拿到tid

    排查过程

    Feign在使用中接入了Hystrix, 所以考虑应该hystrix的问题, 排查中发现zipkin的参数X-B3-TraceId和X-B3-SpanId是可以找到的, 这就有点奇怪了.

    tid排查

    Hystrix使用线程隔离, 所以切换线程的时候, 必须显式的拷贝线程参数, 这个可以用HystrixConcurrencyStrategy来重写hystrix的提交时的操作, 达到拷贝变量的目的, 增加该配置后, tid可以在Feign发送动作中发现

    public class HystrixConcurrencyStrategy extends com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy {
        private static final Logger LOGGER = LoggerFactory.getLogger(HystrixConcurrencyStrategy.class);
    
        @Override
        public <T> Callable<T> wrapCallable(final Callable<T> callable) {
            final Map context = MDC.getCopyOfContextMap();
    
            return new Callable<T>() {
                @Override
                public T call() {
                    Map<String, String> original = MDC.getCopyOfContextMap();
                    if (context != null) {
                        MDC.setContextMap(context);
                    } else {
                        MDC.clear();
                    }
                    try {
                        return callable.call();
                    } catch (Exception e) {
                        LOGGER.error("HttpCallCommand call failed.", e);
                        return null;
                    } finally {
                        if (original != null) {
                            MDC.setContextMap(original);
                        } else {
                            MDC.clear();
                        }
                    }
                }
            };
    
        }
    }
    

    Zipkin变量排查

    既然tid无法做到跨线程, 那Zipkin是怎么做的呢? 同理也是使用了一样的做法, 在SleuthHystrixConcurrencyStrategy中, 将所有的调用Callable做一层包裹, 将需要的参数在调用前通过tracer.continueSpan(span)或者tracer.createSpan(HYSTRIX_COMPONENT)放到对应的MDC中, 达到传递参数的目的

    // Visible for testing
        static class HystrixTraceCallable<S> implements Callable<S> {
    
            private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
    
            private final Tracer tracer;
            private final TraceKeys traceKeys;
            private final Callable<S> callable;
            private final Span parent;
    
            public HystrixTraceCallable(Tracer tracer, TraceKeys traceKeys,
                    Callable<S> callable) {
                this.tracer = tracer;
                this.traceKeys = traceKeys;
                this.callable = callable;
                this.parent = tracer.getCurrentSpan();
            }
    
            @Override
            public S call() throws Exception {
                Span span = this.parent;
                boolean created = false;
                if (span != null) {
                    span = this.tracer.continueSpan(span);
                    if (log.isDebugEnabled()) {
                        log.debug("Continuing span " + span);
                    }
                }
                else {
                    span = this.tracer.createSpan(HYSTRIX_COMPONENT);
                    created = true;
                    if (log.isDebugEnabled()) {
                        log.debug("Creating new span " + span);
                    }
                }
                if (!span.tags().containsKey(Span.SPAN_LOCAL_COMPONENT_TAG_NAME)) {
                    this.tracer.addTag(Span.SPAN_LOCAL_COMPONENT_TAG_NAME, HYSTRIX_COMPONENT);
                }
                String asyncKey = this.traceKeys.getAsync().getPrefix()
                        + this.traceKeys.getAsync().getThreadNameKey();
                if (!span.tags().containsKey(asyncKey)) {
                    this.tracer.addTag(asyncKey, Thread.currentThread().getName());
                }
                try {
                    return this.callable.call();
                }
                finally {
                    if (created) {
                        if (log.isDebugEnabled()) {
                            log.debug("Closing span since it was created" + span);
                        }
                        this.tracer.close(span);
                    }
                    else if(this.tracer.isTracing()) {
                        if (log.isDebugEnabled()) {
                            log.debug("Detaching span since it was continued " + span);
                        }
                        this.tracer.detach(span);
                    }
                }
            }
    

    相关文章

      网友评论

          本文标题:Feign自定义header无法传递

          本文链接:https://www.haomeiwen.com/subject/jlnatqtx.html