Wow4j Wow4j
首页
个人使用说明书
后端开发
前端开发
测试开发
运维开发
大数据开发
产品&UI交互
团队管理
软技能
他山之石
开源产品
敬请期待
GitHub (opens new window)
首页
个人使用说明书
后端开发
前端开发
测试开发
运维开发
大数据开发
产品&UI交互
团队管理
软技能
他山之石
开源产品
敬请期待
GitHub (opens new window)
  • 概要
  • 面试八股文

  • 服务端小技巧合集

    • byte buddy 实现链路上所有方法耗时打印
    • 业务线程池不丢 traceId 的方法
      • 1 背景
      • 2 实现代码
      • 3 效果
    • 让你的java业务代码并发的调用,并正确的处理返回结果
    • 服务端常见线上问题整理与解决措施
    • 服务端日志打印最佳实践
    • 轻松正确理解并上手RESTful
    • 服务端业务线程池优雅使用
    • 服务端如何正确优雅使用流控平台
    • 服务端如何正确的使用分布式锁防止缓存击穿
    • 服务端接口设计最佳实践
  • Java基础

  • MySQL 相关

  • Redis 最佳实践指南

  • 文本搜索Elasticsearch

  • Kafka 最佳实践指南

  • 网络相关

  • 架构相关

  • 监控告警

  • 防爬风控

  • 稳定性 checklist

  • 效能工具

  • 后端开发
  • 服务端小技巧合集
timchen525
2022-03-26

业务线程池不丢 traceId 的方法

# 1 背景


通常,我们会在日志中,通过 traceId 来进行一次完整请求日志的定位,而 traceId 是保存在 MDC 的本地线程中,当主线程开启了一个异步线程时,traceId 就会丢失。本方案,通过线程池中的装饰器,来将父线程中的traceId传递给子线程,从而保证 traceId 不丢失。

# 2 实现代码


/**
 * redis 操作线程池
 */
@Bean(value = "redisOperatorThreadPoolTaskExecutor")
public ThreadPoolTaskExecutor redisOperatorThreadPoolTaskExecutor() {
    // todo 监听线程池使用的情况

    return getThreadPoolTaskExecutor(redisOperatorThreadPoolProperties);
}

/**
 * 根据线程池的属性值获取对应线程的设置
 *
 * @param baseThreadPoolProperties 线程池配置信息
 * @return 线程池
 */
private ThreadPoolTaskExecutor getThreadPoolTaskExecutor(BaseThreadPoolProperties baseThreadPoolProperties) {
    ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
    if (StringUtils.isNotBlank(baseThreadPoolProperties.getThreadGroupName())) {
        threadPoolTaskExecutor.setThreadGroupName(baseThreadPoolProperties.getThreadGroupName());
    }
    if (StringUtils.isNotBlank(baseThreadPoolProperties.getThreadNamePrefix())) {
        threadPoolTaskExecutor.setThreadNamePrefix(baseThreadPoolProperties.getThreadNamePrefix());
    }
    if (null != baseThreadPoolProperties.getCorePoolSize() && baseThreadPoolProperties.getCorePoolSize() > 0) {
        threadPoolTaskExecutor.setCorePoolSize(baseThreadPoolProperties.getCorePoolSize());
    }
    if (null != baseThreadPoolProperties.getQueueCapacity() && baseThreadPoolProperties.getQueueCapacity() > 0) {
        threadPoolTaskExecutor.setQueueCapacity(baseThreadPoolProperties.getQueueCapacity());
    }
    if (null != baseThreadPoolProperties.getMaxPoolSize() && baseThreadPoolProperties.getMaxPoolSize() > 0) {
        threadPoolTaskExecutor.setMaxPoolSize(baseThreadPoolProperties.getMaxPoolSize());
    }
    if (null != baseThreadPoolProperties.getKeepAliveSeconds() && baseThreadPoolProperties.getKeepAliveSeconds() > 0) {
        threadPoolTaskExecutor.setKeepAliveSeconds(baseThreadPoolProperties.getKeepAliveSeconds());
    }
    // 设置拒绝策略
    if (StringUtils.isNotBlank(baseThreadPoolProperties.getRejectedPolicy())) {
        ThreadPoolRejectedPolicyEnum threadPoolRejectedPolicyEnum = ThreadPoolRejectedPolicyEnum.toEnum(baseThreadPoolProperties.getRejectedPolicy());
        if (null != threadPoolRejectedPolicyEnum) {
            threadPoolTaskExecutor.setRejectedExecutionHandler(threadPoolRejectedPolicyEnum.getRejectedExecutionHandler());
        } else {
            log.warn("Not exist rejectedPolicy:{}, return threadPoolRejectedPolicyEnum null.", baseThreadPoolProperties.getRejectedPolicy());
        }
    }
    // 设置MdcRunnable
    threadPoolTaskExecutor.setTaskDecorator(new MdcTaskDecorator());
    return threadPoolTaskExecutor;
}

/**
 * 主线程traceId传入到子线程(注意:线程池池化) 核心代码
 */
private static class MdcTaskDecorator implements TaskDecorator {

    @Override
    public Runnable decorate(Runnable runnable) {
        String traceId = MDC.get(TRACE_ID);
        return () -> {
            try {
                MDC.put(TRACE_ID, traceId);
                runnable.run();
            } finally {
                MDC.remove(TRACE_ID);
            }
        };
    }
}

# 3 效果

异步线程的traceId 和 主线程中的 traceId 一致,从而保证了业务在查看日志时,能够通过 traceId 完成串联一次完整请求的所有日志(包括异步线程中的日志)。

上次更新: 2023/03/22, 15:21:20
byte buddy 实现链路上所有方法耗时打印
让你的java业务代码并发的调用,并正确的处理返回结果

← byte buddy 实现链路上所有方法耗时打印 让你的java业务代码并发的调用,并正确的处理返回结果→

Theme by Vdoing | Copyright © 2022-2023 timchen525 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×