日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 父子线程 调用链_ZipKin原理学习--Zipkin多线程及线程池中追踪一致性问题解决...

發布時間:2025/3/15 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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多线程及线程池中追踪一致性问题解决...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。