当前位置: 首页 > news >正文

一次解决ForkJoinPool日志追踪的辛酸经历

本文主要分享了一次解决ForkJoinPool日志追踪的辛酸经历。历时3个月终于找到通用的解决方案,以此文分享给有需要的你。

一、需求背景

1.某日,某同事根据日志ID排查生产环境问题过程中,发现日志不全

2.经排查发现中间有很多线程为ForkJoinPool.commonPool-worker的日志ID是丢失的

3.经代码review,发现这些丢失日志ID的log.info都是在parallelStream代码块中的

4.经了解,因为使用了parallelStream并发处理集合数据,这样能够提升接口性能,并且这个功能是jdk提供的,使用非常方便

以下为简化版的代码demo

经测试,发现在parallelStream的log.info无法正确的打印日志ID,那么在生产环境中,日志ID的丢失意味着日志排查问题变得困难,如下图所示

二、原因分析

为了提升接口性能,使用并发编程加快查询速度的确是比较不错的方案。

日志ID是使用org.slf4j.MDC进行传递的,经阅读源码,发现底层是使用ThreadLocal来进行数据存储的,多线程情况下,子线程无法访问到主线程的日志ID

并发编程项目中通常有2种用法:

1.使用线程池,如ThreadPoolExecutor、ThreadPoolTaskExecutor,可以自己new一个实例,这样的话可以通过自定义子类来做日志ID传递(这种方式已解决,具体可阅文章,这里就不详说了:https://www.toutiao.com/article/7126056949267268108)

2.使用ForkJoinPool,不是由自己new实例,而是jdk封装好的。例如CompletableFuture、list.parallelStream()、list.stream().parallel()等,底层都是使用了ForkJoinPool作为线程池实现(为了找到通用的解决方案,历时3个月)

>>> 那如何解决ForkJoinPool这个日志ID丢失的问题?

三、临时方案

当时无法在短时间内快速找到通用解决方案,所以想了1种临时方案:通过变量的方式传递到list.parallelStream()内部

如下图,这种方案需要改动代码

为什么要加subTraceId == null的判断?

答:主线程也会作为ForkJoinPool执行的一部分,主线程的日志ID不能清,否则后续的日志ID会丢失

四、寻找通用方案

1.方向错误,努力白费(辛酸经历,中途还想过放弃寻找通用方案)

方向1:参考ThreadPoolExecutor、ThreadPoolTaskExecutor,想办法自己new一个ForkJoinPool的实例,然后添加到spring容器使用

结果:最终发现ForkJoinPool是内部实现了1个静态的实例common从而告败

方向2:使用javaagent的方式修改ForkJoinPool或者其任务 ForkJoinTask等相关类的字节码,此想法来自一篇好文:一次「找回」TraceId的问题分析与过程思考(一次「找回」TraceId的问题分析与过程思考)

结果:最终发现字节码框架Javassist底层对包名以java.开头的所有类进行了保护,而ForkJoinPool的包名java.util.concurrent,所以字节码修改方案也不通了

2.求助网友,集思广益

真的挺感谢这位‘新手村NPC’网友,给我提供了1个思路:竟然修改ForkJoinPool的思路走不通,那就尝试修改日志组件

3.修改日志组件

1.前面说过MDC底层是使用ThreadLocal来进行数据存储的,这就让我想到了阿里的TransmittableThreadLocal,能够在父子线程之间传递数据

先测试一下TransmittableThreadLocal能否在list.parallelStream()内部正确传递数据

注:需要在启动命令上加上:-javaagent:path/to/transmittable-thread-local-2.x.x.jar(替换为你maven路径中jar路径即可),否则会读取不到,因为TransmittableThreadLocal是基于字节码javaagent来实现的

结果:输出的值始终保持一致

2.修改MDC

MDC的ThreadLocal在哪里?通过断点的方式找到了MDCAdapter的实例LogbackMDCAdapter(其成员变量copyOnThreadLocal)

有没有办法在初始化时替换掉这个MDCAdapter的实例?MDCAdapter下面的MDCAdapter不是public的,只有getMDCAdapter方法而没有setMDCAdapter方法。

于是网上查询相关资料,方案是在项目中写个org.slf4j的包,然后通过以下方式赋值,因为同包下可访问(不得不说这操作挺骚的,佩服,这些知识点都忘了)

然后通过TtlMdcListener对TtlMDCAdapter进行实例化

logback.xml配置文件中增加TtlMdcListener的实例化

<contextListener class="com.ofpay.logback.TtlMdcListener"/>

这2个简单的类,既可以自己实现,也可以使用开源的maven,实现原理是一样的

<dependency><groupId>com.ofpay</groupId><artifactId>logback-mdc-ttl</artifactId><version>1.0.2</version>
</dependency>

于是,在完全不改业务代码的情况下,日志ID正确地传递下来了

测试结果:

怎么样?如果你觉得有用的话,还不快快收藏起来!!!

附:涉及的代码目录

github: https://github.com/897665787/springcloud-template

gitee:springcloud-template: 一个基于springcloud netflix微服务框架,记录了关于微服务开发的一些最佳应用,欢迎大家学习指导。

springcloud-template

└── template-common

     └──src/main/resources

          └── logback-conf-base.xml-- 日志配置

     └──pom.xml-- 引用logback-mdc-ttl

└── template-web

     └──controller

          └── TraceIdController-- 日志ID测试demo

相关文章:

一次解决ForkJoinPool日志追踪的辛酸经历

本文主要分享了一次解决ForkJoinPool日志追踪的辛酸经历。历时3个月终于找到通用的解决方案&#xff0c;以此文分享给有需要的你。 一、需求背景 1.某日&#xff0c;某同事根据日志ID排查生产环境问题过程中&#xff0c;发现日志不全 2.经排查发现中间有很多线程为ForkJoinP…...

VM使用教程--SDK取图 视频笔记

本笔记均由海康机器人官网的V学院视频中记录所得&#xff0c;属于省流大师了[doge] 图像采集 图像采集包括1图像源&#xff0c;2多图采集&#xff0c;3输出图像&#xff0c;4缓存图像&#xff0c;5光源 1图像源 图像源包括本地图像&#xff0c;相机采图&#xff0c;SDK 本…...

11.spring boot 启动源码(一)

目录 概述SpringApplication静态方法构造方法run 实例方法配置文件Actuator 工作原理*EndpointAutoConfigurationBeansEndpointAutoConfigurationShutdownEndpointAutoConfiguration结束概述 spring boot 版本 2.6.13 spring boot 启动源码(一) 涉及 SpringApplication 中静态…...

【微服务】springcloud集成sleuth与zipkin实现链路追踪

目录 一、前言 二、分布式链路调用问题 三、链路追踪中的几个概念 3.1 什么是链路追踪 3.2 常用的链路追踪技术 3.3 链路追踪的几个术语 3.3.1 span ​编辑 3.3.2 trace 3.3.3 Annotation 四、sluth与zipkin概述 4.1 sluth介绍 4.1.1 sluth是什么 4.1.2 sluth核心…...

数学建模-预测人口数据

目录 中国09~18年人口数据 创建时间 绘制时间序列图 使用专家建模器 得到结果 预测结果 残差的白噪声检验 中国09~18年人口数据 创建时间 路径&#xff1a;数据-> 定义日期和时间 绘制时间序列图 使用专家建模器 看看spss最终判断是那个模型最佳的契合 得到结果 预…...

SpringBoot 集成 Canal 基于 MySQL 做数据同步

一、canal 组件关系 下载地址&#xff1a;https://github.com/alibaba/canal/releases/download/canal-1.1.7/ 这里面主要的有两个 canal.deployer-1.1.7.tar.gz 和 canal.adapter-1.1.7.tar.gz&#xff0c;canal.admin-1.1.7.tar.gz 是一个监控服务&#xff0c;可选&#xf…...

【CVE-2022-22733漏洞复现】

Apache ShardingSphere ElasticJob-UI漏洞 漏洞编号:CVE-2022-22733 文档说明 本文作者:SwBack 创作时间:2024/1/21 19:19:19 知乎:https://www.zhihu.com/people/back-88-87 CSDN:https://blog.csdn.net/qq_30817059 百度搜索: SwBack漏洞描述 Apache ShardingSphere Elast…...

Python爬虫---scrapy框架---当当网管道封装

项目结构&#xff1a; dang.py文件&#xff1a;自己创建&#xff0c;实现爬虫核心功能的文件 import scrapy from scrapy_dangdang_20240113.items import ScrapyDangdang20240113Itemclass DangSpider(scrapy.Spider):name "dang" # 名字# 如果是多页下载的话, …...

【机器学习】机器学习四大类第01课

一、机器学习四大类 有监督学习 (Supervised Learning) 有监督学习是通过已知的输入-输出对&#xff08;即标记过的训练数据&#xff09;来学习函数关系的过程。在训练阶段&#xff0c;模型会根据这些示例调整参数以尽可能准确地预测新的、未见过的数据点的输出。 实例&#x…...

下述默认构造函数有什么问题?

12.4 // points to string allocated by new // holds length of string 独立的、相同的数据,而不会重叠。由于同样的原因,必须定义赋值操作符。对于每一种情况,最终目的 都是执行深度复制,也就是说,复制实际的数据,而不仅仅是复制指向数据的指针。 对象的存储持续性为自动或…...

vite和mockjs配合使用

vite mockjs 当后端还没准备完成之前&#xff0c;前端可以使用 mock 模拟后端响应&#xff0c;提高开发效率 1、安装插件 使用 vite-plugin-mock 插件&#xff0c;配合mockjs完成项目的 mock 配置 npm install mockjs vite-plugin-mock2、vite配置插件 在 vite.config.js…...

【数据结构】常见八大排序算法总结

目录 前言 1.直接插入排序 2.希尔排序 3.选择排序 4.堆排序 5.冒泡排序 6.快速排序 6.1Hoare版本 6.2挖坑法 6.3前后指针法 6.4快速排序的递归实现 6.5快速排序的非递归实现 7.归并排序 8.计数排序&#xff08;非比较排序&#xff09; 9.补充:基数排序 10.总结…...

系统学英语 — 句法 — 常规句型

目录 文章目录 目录5 大基本句型复合句型主语从句宾语从句表语从句定语从句状语从句同位语从句补语从句 谓语句型 5 大基本句型 主谓&#xff1a;主语发出一个动作&#xff0c;例如&#xff1a;He cried.主谓宾&#xff1a;we study English.主系表&#xff1a;主语具有某些特…...

Github操作网络异常笔记

Github操作网络异常笔记 1. 源由2. 解决2.1 方案一2.2 方案二 3. 总结 1. 源由 开源技术在国内永远是“蛋疼”&#xff0c;这些"政治"问题对于追求技术的我们&#xff0c;形成无法回避的障碍。 $ git pull ssh: connect to host github.com port 22: Connection ti…...

Vue3新特性defineModel()便捷的双向绑定数据

官网介绍 传送门 配置 要求&#xff1a; 版本&#xff1a; vue > 3.4(必须&#xff01;&#xff01;&#xff01;)配置&#xff1a;vite.config.js 使用场景和案例 使用场景&#xff1a;父子组件的数据双向绑定&#xff0c;不用emit和props的繁重代码 具体案例 代码实…...

vue列表飞入效果

效果 实现代码 <template><div><button click"add">添加</button><TransitionGroup name"list" tag"ul"><div class"list-item" v-for"item in items" :key"item.id">{{ i…...

C语言·预处理详解

1. 预定义符号 C语言设置了一些预定义符号&#xff0c;可以直接使用&#xff0c;预定义符号也是在预处理期间处理的 __FILE__ 进行编译的源文件 __LINE__ 文件当前的行号 __DATE__ 文件被编译的日期 __TIME__ 文件被编译的时间 __STDC__ 如果编译器遵循ANSI C&#xff0c;…...

服务器与普通电脑的区别,普通电脑可以当作服务器用吗?

服务器在我们日常应用中非常常见&#xff0c;手机APP、手机游戏、PC游戏、小程序、网站等等都需要部署在服务器上&#xff0c;为我们提供各种计算、应用服务。服务器也是计算机的一种&#xff0c;虽然内部结构相差不大&#xff0c;但是服务器的运行速度更快、负载更高、成本更高…...

数字身份所有权:Web3时代用户数据的掌控权

随着Web3时代的来临&#xff0c;数字身份的概念正焕发出崭新的光芒。在这个数字化的时代&#xff0c;用户的个人数据变得愈加珍贵&#xff0c;而Web3则为用户带来了数字身份所有权的概念&#xff0c;重新定义了用户与个人数据之间的关系。本文将深入探讨Web3时代用户数据的掌控…...

python爬虫如何写,有哪些成功爬取的案例

编写Python爬虫时&#xff0c;常用的库包括Requests、Beautiful Soup和Scrapy。以下是三个简单的Python爬虫案例&#xff0c;分别使用Requests和Beautiful Soup&#xff0c;以及Scrapy。 1. 使用Requests和Beautiful Soup爬取网页内容&#xff1a; import requests from bs4 …...

一键获取九大网盘真实下载地址:LinkSwift网盘直链下载助手完整指南

一键获取九大网盘真实下载地址&#xff1a;LinkSwift网盘直链下载助手完整指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动…...

大疆L1点云与ContextCapture融合实战:从Sbet轨迹到三维实景模型的完整数据流

1. 大疆L1点云与ContextCapture融合的核心价值 如果你手头有大疆L1激光雷达采集的点云数据&#xff0c;想要在ContextCapture&#xff08;现在叫iTwin Capture&#xff09;里生成高精度三维模型&#xff0c;但卡在了轨迹文件转换这一步&#xff0c;那这篇文章就是为你准备的。…...

使用curl命令直接测试taotoken api的连通性与基础功能

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 使用curl命令直接测试taotoken api的连通性与基础功能 基础教程类&#xff0c;面向需要快速验证或在不便安装SDK的环境中进行操作的…...

树莓派TFT LCD屏幕连接全攻略:从SPI到DPI的选型与驱动配置

1. 项目概述&#xff1a;为什么是TFT LCD与树莓派&#xff1f; 如果你玩过树莓派&#xff0c;大概率会从一块小小的HDMI显示器或者SSH终端开始。但当你想要做一个便携的天气站、一个复古游戏机&#xff0c;或者一个嵌入在机器人里的控制面板时&#xff0c;拖着笨重的HDMI显示器…...

【DeepSeek×GCP联合认证部署方案】:谷歌云架构师与DeepSeek官方工程师联名验证的3种生产级拓扑

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;DeepSeek GCP部署指南 在Google Cloud Platform上部署DeepSeek系列大语言模型&#xff08;如DeepSeek-V2、DeepSeek-Coder&#xff09;需兼顾计算性能、存储效率与网络低延迟。本指南基于GCP的Vertex AI平台与…...

AMD游戏本ChinaJoy三连发:从3D V-Cache到性价比旗舰的全面解析

1. 项目概述&#xff1a;ChinaJoy 2023上的AMD游戏本盛宴每年ChinaJoy不仅是游戏玩家的狂欢&#xff0c;更是硬件厂商展示肌肉的舞台。今年&#xff0c;这个舞台的主角无疑是AMD。当大家还在讨论移动端处理器核心数大战时&#xff0c;AMD直接甩出了“缓存为王”的王炸&#xff…...

BepInEx框架指南:从游戏玩家到模组开发者的完整升级路径

BepInEx框架指南&#xff1a;从游戏玩家到模组开发者的完整升级路径 【免费下载链接】BepInEx Unity / XNA game patcher and plugin framework 项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx 你是否曾经羡慕过那些能够为游戏添加新内容、修改界面、甚至创…...

前端正则表达式(?:pattern)的具体使用和介绍

文章目录一、官方解释二、js代码例子解释参考文档一、官方解释 (?:pattern) 是正则表达式中的一种结构&#xff0c;称为“非捕获组”&#xff08;Non-Capturing Group&#xff09;。它允许您将多个字符或子表达式组合在一起&#xff0c;作为一个整体对待&#xff0c;而不捕获…...

Layerdivider深度解析:5步实现智能图像分层,生成专业级PSD文件

Layerdivider深度解析&#xff1a;5步实现智能图像分层&#xff0c;生成专业级PSD文件 【免费下载链接】layerdivider A tool to divide a single illustration into a layered structure. 项目地址: https://gitcode.com/gh_mirrors/la/layerdivider Layerdivider是一款…...

Embulk高级用法指南:如何实现高效并行处理与数据分片

Embulk高级用法指南&#xff1a;如何实现高效并行处理与数据分片 【免费下载链接】embulk Embulk: Pluggable Bulk Data Loader. 项目地址: https://gitcode.com/gh_mirrors/em/embulk Embulk是一个强大的可插拔批量数据加载器&#xff0c;专为高效处理大规模数据迁移而…...