问题描述
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);
}
}
}
网友评论