java 父子线程 调用链_ZipKin原理学习--Zipkin多线程及线程池中追踪一致性问题解决...
在學習Zipkin分布式追蹤系統中我們了解到Trace在整個調用鏈是一致的,在web服務中可以通過在header設置Trace值在不同的服務中進行傳遞,那樣在一個服務內部不同的線程,甚至是線程池中Zipkin是如何處理的,接下來我們來了解學習一下。
單個線程
在單個線程的調用過程中,我們一般都知道通過ThreadLocal來完成在整個線程執行過程中獲取相同的Trace值,Zipkin也是通過定義了一個ThreadLocal local來實現處理的。
父子線程
在主線程中新建立一個子線程時使用ThreadLocal就無效了,因此Zipkin提供了如下定義方式,使用InheritableThreadLocal定義(可以參考博客Java 多線程:InheritableThreadLocal 實現原理)
static final InheritableThreadLocal INHERITABLE = new InheritableThreadLocal<>();
這樣就是存在父子線程,在創建子線程的過程中會將父線程的值全部拷貝到子線程中,這樣在子線程中依然可以獲取到Trace值,因此如下面的代碼追蹤鏈路依然是完整的。
@RequestMapping("/start2")
public String start(HttpServletRequest request1,HttpServletResponse response1) throws InterruptedException, IOException {
Thread thread = new Thread((new Runnable() {
@Override
public void run() {
System.err.println(Thread.currentThread().hashCode());
data = restTemplate.getForObject("http://localhost:9090/foo", String.class);
}
}));
thread.start();
return data;
}
線程池
在我們新創建一個線程,然后將線程提交給線程池時,由于線程池中線程執行的原理此時原線程中的ThreadLocal和InheritableThreadLocal都是無效的,追蹤Trace值因此會丟失,導致整個調用鏈出現斷路,如下面代碼。
@RequestMapping("/start2")
public String start(HttpServletRequest request1,HttpServletResponse response1) throws InterruptedException, IOException {
String data = "";
Thread thread = new Thread((new Runnable() {
@Override
public void run() {
System.err.println(Thread.currentThread().hashCode());
data = restTemplate.getForObject("http://localhost:9090/foo", String.class);
}
}));
executor.execute(thread);
Thread.sleep(10000);
return data;
}
目前Zipkin類CurrentTraceContext給出對線程及線程池的的處理方法就是實現了Runnable重新實現了run方法,這樣就解決了線程池的問題,當然不只提供了創建線程的方法,還包括線程池和Callable
public Runnable wrap(Runnable task) {
//獲取父線程中的Trace
final TraceContext invocationContext = get();
class CurrentTraceContextRunnable implements Runnable {
@Override public void run() {
//將父線程中的Trace復制到子線程中
try (Scope scope = maybeScope(invocationContext)) {
task.run();
}
}
}
return new CurrentTraceContextRunnable();
}
public Scope maybeScope(@Nullable TraceContext currentSpan) {
TraceContext currentScope = get();
if (currentSpan == null) {
if (currentScope == null) return Scope.NOOP;
return newScope(null);
}
return currentSpan.equals(currentScope) ? Scope.NOOP : newScope(currentSpan);
}
public Executor executor(Executor delegate) {
class CurrentTraceContextExecutor implements Executor {
@Override public void execute(Runnable task) {
delegate.execute(CurrentTraceContext.this.wrap(task));
}
}
return new CurrentTraceContextExecutor();
}
/**
* Decorates the input such that the {@link #get() current trace context} at the time a task is
* scheduled is made current when the task is executed.
*/
public ExecutorService executorService(ExecutorService delegate) {
class CurrentTraceContextExecutorService extends brave.internal.WrappingExecutorService {
@Override protected ExecutorService delegate() {
return delegate;
}
@Override protected Callable wrap(Callable task) {
return CurrentTraceContext.this.wrap(task);
}
@Override protected Runnable wrap(Runnable task) {
return CurrentTraceContext.this.wrap(task);
}
}
return new CurrentTraceContextExecutorService();
}
public Callable wrap(Callable task) {
final TraceContext invocationContext = get();
class CurrentTraceContextCallable implements Callable {
@Override public C call() throws Exception {
try (Scope scope = maybeScope(invocationContext)) {
return task.call();
}
}
}
return new CurrentTraceContextCallable();
}
總結
以上是生活随笔為你收集整理的java 父子线程 调用链_ZipKin原理学习--Zipkin多线程及线程池中追踪一致性问题解决...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python curl 获取返回值_py
- 下一篇: python编译2的n次方计算器_用PY