在学习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多线程及线程池中追踪一致性问题解决...相关推荐

  1. vivo 调用链 Agent 原理及实践

    一.项目背景 2017年,vivo互联网研发团队认为调用链系统对实际业务具有较大的价值,于是开始了研发工作.3年的时间,调用链系统整体框架不断演进--本文将介绍vivo调用链系统 Agent 技术原理 ...

  2. 微服务调用链的原理和选型

    原文:https://juejin.im/post/5cde874e6fb9a07f091b713c 微服务是一个分布式非常复杂系统,如果没有一套调用链监控,如果服务之间依赖出现问题就很难进行调位 下 ...

  3. VC++中多线程学习(MFC多线程)一(线程的创建、线程函数如何调用类成员呢?如何调用主对话框的成员?、MFC中的工作线程和界面线程的区别)

    这里废话不多讲了,因为项目原因,需要开启线程进行处理,在不了解线程的情况下,直接百度一下,然后就使用了,结果可想而知,出现了异常,所以花了一天时间系统学习一下多线程,这里主要是针对win32编程方面的 ...

  4. VC++中多线程学习(MFC多线程)二(线程的相关操作、线程间的通信)

    上一篇笼统介绍了如何创建线程以及线程如何和类成员函数通信,本篇将主要介绍: 线程的相关操作 1.线程的挂起和恢复:SuspendThread.ResumeThread 在线程创建并运行后,用户可以对线 ...

  5. ZipKin原理学习--ZipKin入门介绍

    ZipKin入门介绍 Zipkin是一款开源的分布式实时数据追踪系统(Distributed Tracking System),基于 Google Dapper的论文设计而来,由 Twitter 公司 ...

  6. JAVA入门基础进阶(十四)—— 实现多线程、线程同步、生产者消费者

    文章目录 1.实现多线程 1.1简单了解多线程[理解] 1.2并发和并行[理解] 1.3进程和线程[理解] 1.4实现多线程方式一:继承Thread类[应用] 1.5实现多线程方式二:实现Runnab ...

  7. 为什么不能线程调用类的成员函数_C++多线程编程之创建线程的几种方法

    点蓝色字关注"CurryCoder的程序人生" 微信公众号:CurryCoder的程序人生 怕什么真理无穷,进一寸有一寸的欢喜 1.线程基础知识 可执行程序运行起来,就会生成一个进 ...

  8. 【java并发编程艺术学习】(四)第二章 java并发机制的底层实现原理 学习记录(二) synchronized...

    章节介绍 本章节主要学习 Java SE 1.6 中为了减少获得锁 和 释放锁 时带来的性能消耗 而引入的偏向锁 和 轻量级锁,以及锁的存储结构 和 升级过程. synchronized实现同步的基础 ...

  9. java静态函数调用,书籍+视频+学习笔记+技能提升资源库

    腾讯 一面(支付) 1.jqc的介绍 2.如何确保多台机器不会重复消费 3.如何确保消费了反馈失效问题(用事务管理,先储存再消费,失败就回滚) 4.如何防止数据库单点问题 8.paxos算法 9.ra ...

最新文章

  1. pg数据库json数据类型_PG数据类型
  2. Jboss解决只能通过localhost访问而不能使用IP访问项目的问题
  3. 一个小改动,CNN输入固定尺寸图像改为任意尺寸图像
  4. [转]C#中使用Monitor类、Lock和Mutex类来同步多线程的执行
  5. springcloud13---zuul
  6. linux修改时间指令,Linux 修改时间的指令
  7. 团队任务3:每日立会(2018-10-25)
  8. android中获取时间
  9. Cocos2d-x 3 X CMake MinGW版本编译运行
  10. 双线程交替修改变量 条件变量
  11. To shade or not to shade
  12. MySQL 5.7安装配置方法
  13. IIS Express加入MIME映射
  14. [RTMP协议]常用直播流地址
  15. 迪士尼超级IP版图日趋完整
  16. 阿里巴巴全资收购中国网络配送平台饿了么
  17. java实现屏幕截图
  18. libGDX游戏开发之NPC敌人事件(六)
  19. Apache ShenYu网关初体验
  20. ClassNotFoundException:com.tongweb.geronimo.osgi.locator.ProviderLocator

热门文章

  1. XSSFWorkbook与HSSFWorkbook的区别
  2. 鸿蒙构架谁提供的,科普丨关于“鸿蒙”,不知道这些你都不好意思跟别人打招呼!...
  3. dateframe取某列数据_Python获取时序数据并进行可视化分析
  4. android关机背景,鍵盤消失后的Android白色背景
  5. python寻找多数元素_寻找多数元素
  6. 算法设计中的基础常用代码
  7. MySQL日期类型的处理总结
  8. java 自动类型_java类型自动转换
  9. 高考python必考题目_假如高考考python编程,这些题目你会几个呢?
  10. layout布局_安卓最常见的几种布局