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

增加网站访客seo课程培训机构

增加网站访客,seo课程培训机构,安阳县人民政府,梅河口市建设局网站本文主要分享了一次解决ForkJoinPool日志追踪的辛酸经历。历时3个月终于找到通用的解决方案,以此文分享给有需要的你。 一、需求背景 1.某日,某同事根据日志ID排查生产环境问题过程中,发现日志不全 2.经排查发现中间有很多线程为ForkJoinP…

本文主要分享了一次解决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

http://www.hkea.cn/news/757246/

相关文章:

  • 虚拟币网站开发seo百度关键字优化
  • 网站建设都 包括哪些淄博网站制作
  • 自己做装修网站南宁百度推广seo
  • 品牌建设浅谈seo网络营销外包
  • 昆山网站建设兼职千锋教育的官网
  • cm域名做网站盘古百晋广告营销是干嘛
  • 网站栏目策划企业网络营销方案
  • 网站自动采集指标sem广告投放是做什么的
  • 想做一个个人网站怎么做培训学校
  • 网站开发ipv6升级如何创建自己的小程序
  • 做网站需要备案吗外贸网站推广与优化
  • 独立网站建设流程b站视频推广网站动漫
  • 泰安诚信的网站建设b站推广入口2023年
  • 高校网站建设资料库东莞seo推广公司
  • 电子印章手机在线制作软件四川seo整站优化费用
  • 个人风采网站制作外贸网站平台哪个好
  • 沈阳企业建站谷歌推广和seo
  • .la域名做的网站如何快速推广app
  • 广州优化网站建设怎么用手机制作网站
  • 做微网站的第三方学网络营销
  • 湖南做网站的公司有哪些搜索引擎是什么
  • flash网站管理系统seo优化排名易下拉用法
  • 永年网站建设友链互换平台推荐
  • 企业网站的设计公司网络广告营销的典型案例
  • 高校思政主题网站建设的意义关键词歌词任然
  • 哪里做网站比较快2345网址导航下载桌面
  • 广州建设委员会官方网站凡科建站下载
  • 全球做网站的公司排名百度一下你就知道官网
  • 小企业网站价格免费发链接的网站
  • 买了空间和域名 怎么做网站哪家公司网站做得好