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多线程及线程池中追踪一致性问题解决...相关推荐
- vivo 调用链 Agent 原理及实践
一.项目背景 2017年,vivo互联网研发团队认为调用链系统对实际业务具有较大的价值,于是开始了研发工作.3年的时间,调用链系统整体框架不断演进--本文将介绍vivo调用链系统 Agent 技术原理 ...
- 微服务调用链的原理和选型
原文:https://juejin.im/post/5cde874e6fb9a07f091b713c 微服务是一个分布式非常复杂系统,如果没有一套调用链监控,如果服务之间依赖出现问题就很难进行调位 下 ...
- VC++中多线程学习(MFC多线程)一(线程的创建、线程函数如何调用类成员呢?如何调用主对话框的成员?、MFC中的工作线程和界面线程的区别)
这里废话不多讲了,因为项目原因,需要开启线程进行处理,在不了解线程的情况下,直接百度一下,然后就使用了,结果可想而知,出现了异常,所以花了一天时间系统学习一下多线程,这里主要是针对win32编程方面的 ...
- VC++中多线程学习(MFC多线程)二(线程的相关操作、线程间的通信)
上一篇笼统介绍了如何创建线程以及线程如何和类成员函数通信,本篇将主要介绍: 线程的相关操作 1.线程的挂起和恢复:SuspendThread.ResumeThread 在线程创建并运行后,用户可以对线 ...
- ZipKin原理学习--ZipKin入门介绍
ZipKin入门介绍 Zipkin是一款开源的分布式实时数据追踪系统(Distributed Tracking System),基于 Google Dapper的论文设计而来,由 Twitter 公司 ...
- JAVA入门基础进阶(十四)—— 实现多线程、线程同步、生产者消费者
文章目录 1.实现多线程 1.1简单了解多线程[理解] 1.2并发和并行[理解] 1.3进程和线程[理解] 1.4实现多线程方式一:继承Thread类[应用] 1.5实现多线程方式二:实现Runnab ...
- 为什么不能线程调用类的成员函数_C++多线程编程之创建线程的几种方法
点蓝色字关注"CurryCoder的程序人生" 微信公众号:CurryCoder的程序人生 怕什么真理无穷,进一寸有一寸的欢喜 1.线程基础知识 可执行程序运行起来,就会生成一个进 ...
- 【java并发编程艺术学习】(四)第二章 java并发机制的底层实现原理 学习记录(二) synchronized...
章节介绍 本章节主要学习 Java SE 1.6 中为了减少获得锁 和 释放锁 时带来的性能消耗 而引入的偏向锁 和 轻量级锁,以及锁的存储结构 和 升级过程. synchronized实现同步的基础 ...
- java静态函数调用,书籍+视频+学习笔记+技能提升资源库
腾讯 一面(支付) 1.jqc的介绍 2.如何确保多台机器不会重复消费 3.如何确保消费了反馈失效问题(用事务管理,先储存再消费,失败就回滚) 4.如何防止数据库单点问题 8.paxos算法 9.ra ...
最新文章
- pg数据库json数据类型_PG数据类型
- Jboss解决只能通过localhost访问而不能使用IP访问项目的问题
- 一个小改动,CNN输入固定尺寸图像改为任意尺寸图像
- [转]C#中使用Monitor类、Lock和Mutex类来同步多线程的执行
- springcloud13---zuul
- linux修改时间指令,Linux 修改时间的指令
- 团队任务3:每日立会(2018-10-25)
- android中获取时间
- Cocos2d-x 3 X CMake MinGW版本编译运行
- 双线程交替修改变量 条件变量
- To shade or not to shade
- MySQL 5.7安装配置方法
- IIS Express加入MIME映射
- [RTMP协议]常用直播流地址
- 迪士尼超级IP版图日趋完整
- 阿里巴巴全资收购中国网络配送平台饿了么
- java实现屏幕截图
- libGDX游戏开发之NPC敌人事件(六)
- Apache ShenYu网关初体验
- ClassNotFoundException:com.tongweb.geronimo.osgi.locator.ProviderLocator
热门文章
- XSSFWorkbook与HSSFWorkbook的区别
- 鸿蒙构架谁提供的,科普丨关于“鸿蒙”,不知道这些你都不好意思跟别人打招呼!...
- dateframe取某列数据_Python获取时序数据并进行可视化分析
- android关机背景,鍵盤消失后的Android白色背景
- python寻找多数元素_寻找多数元素
- 算法设计中的基础常用代码
- MySQL日期类型的处理总结
- java 自动类型_java类型自动转换
- 高考python必考题目_假如高考考python编程,这些题目你会几个呢?
- layout布局_安卓最常见的几种布局