美文网首页
线程池分布式追踪方案实现

线程池分布式追踪方案实现

作者: java_飞 | 来源:发表于2020-12-31 11:24 被阅读0次

场景:在生产环境种,查询发现错误日志时,需要定位跟踪到最终问题,但是项目种用到了很多的异步线程池,导致定位问题时根据traceId,只能找到一部分日志内容,无法最终定位到问题所在;

原因:这是由于MDC的实现是通过ThreadLocal实现的,然后线程池种的线程和用户线程不是同一个线程,所以在异步调用的时候,用户线程的内容没有同步到线程池线程中,导致最终没有打印出关联的tracId,从而导致最终无法关联相关日志,无法定位到具体问题;

解决方案:因为实现异步的方式有很多种,例如线程池和ThreadPoolExecutor和ThreadPoolTaskExecutor,spring的@Aync等,但是根本原因都是因为两个线程不是同一个线程引起的,所以我这里只例举线程池ThreadPoolExecutor的实现,其他实现相差无几;
ThreadMdcUtil.class

import org.slf4j.MDC;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * className:ThreadMdcUtil
 * description: mdcUtil
 *
 * @author: david
 * date: 2020/12/31 10:42 上午
 */
public class ThreadMdcUtil {


    public static <T> Callable<T> wrap(final Callable<T> callable, final Map<String, String> context) {
        return () -> {
            if (context == null) {
                MDC.clear();
            } else {
                MDC.setContextMap(context);
            }
            try {
                return callable.call();
            } finally {
                MDC.clear();
            }
        };
    }

    public static Runnable wrap(final Runnable runnable, final Map<String, String> context) {
        return () -> {
            if (context == null) {
                MDC.clear();
            } else {
                MDC.setContextMap(context);
            }
            try {
                runnable.run();
            } finally {
                MDC.clear();
            }
        };
    }
}

ThreadPoolExecutorMdcWrapper.class

import org.slf4j.MDC;
import java.util.concurrent.*;

/**
 * className:ThreadPoolExecutorMdcWrapper
 * description: 线程池包装类
 *
 * @author: david
 * date: 2020/12/31 10:41 上午
 */
public class ThreadPoolExecutorMdcWrapper extends ThreadPoolExecutor {
    public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                        BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                        BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                        BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                        BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
                                        RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    @Override
    public void execute(Runnable task) {
        super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    }

    @Override
    public <T> Future<T> submit(Runnable task, T result) {
        return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()), result);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    }

    @Override
    public Future<?> submit(Runnable task) {
        return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    }
}

具体使用方式如下:
在需要使用线程池的时候,使用ThreadPoolExecutorMdcWrapper类创建线程池去执行相关逻辑;

相关文章

  • 线程池分布式追踪方案实现

    场景:在生产环境种,查询发现错误日志时,需要定位跟踪到最终问题,但是项目种用到了很多的异步线程池,导致定位问题时根...

  • 高并发下Java多线程编程基础

    Java线程同步与异步 线程池 无锁化的实现方案 分布锁的实现方案 分享的目的: 进一步掌握多线程编程和应用的技巧...

  • 分布式追踪系统之Jaeger 实现

    分布式追踪OpenTracing与 Jaeger 实现

  • 线程以及java线程池实现分享

    线程以及java线程池实现分享 线程简介 JDK线程池的工作原理 JDK线程池的实现细节 1.线程简介-由来 1....

  • java多线程面试题

    实现多线程的方法 1.实现Thread接口 2.实现Runnable接口创建线程 3.实现 线程池 创建线程池的代...

  • 不怕难之线程池原理

    一、线程池状态 ThreadPoolExecutor 是 JDK 中的线程池实现,这个类实现了一个线程池需要的各个...

  • 线程池的原理

    参考 深入Java源码理解线程池原理 线程池是对CPU利用的优化手段 线程池使用池化技术实现,替他的实现还有连接池...

  • Java核心(二)深入理解线程池ThreadPool

    本文你将获得以下信息: 线程池源码解读 线程池执行流程分析 带返回值的线程池实现 延迟线程池实现 为了方便读者理解...

  • 2021-02-20

    1.介绍一下自己,聊项目,聊优化方案,聊分布式事务 2.知道哪些线程池?什么时候到达最大线程数?到达最大线程后继续...

  • java基础-多线程

    java线程池的实现 ThreadPoolExecutor java线程池几个参数 corePoolSize当线程...

网友评论

      本文标题:线程池分布式追踪方案实现

      本文链接:https://www.haomeiwen.com/subject/umuloktx.html