transmittable-thread-local在slf4j中解决MDC线程池中上下文传递

1,211 阅读3分钟

目录

TTL描述了四种场景

TTL在日志收集系统的两种实现

TTL在snowball-common中的应用

应用升级snowball-common


 

直接我球docs粘过来的,我不用写两份,欢迎投递简历:github.com/singgel  

transmittable-thread-local以下简称:TTL

根据InheritableThreadLocal在线程池中上下文传递的问题可以知道这个threadLocal的值传递,在父子线程之间若使用了线程池的技术,会导致子线程的threadLocal信息错乱。

根据分布式追踪系统场景下,如何使用TTL 知道ttl的实现原理,通过线程池的封装,threadLocal的继承实现了traceId的传递,采用weakHashMap取代引用计数的方法实现了GC的回收防止内存泄漏。

 

以下具体问题具体分析,给出的是以agent方式代码无侵入接入

 

TTL描述了四种场景

  1. 分布式跟踪系统
  2. 日志收集记录系统上下文
  3. SessionCache
  4. 应用容器或上层框架跨应用代码给下层SDK传递信息

分布式跟踪系统

snowball-common里的traceId是不是TTL推荐的分布式追踪系统场景下,如何使用TTL ,根据issue的描述,文章讲的是分布式追踪相关的设计和ttl在其中的应用,而在snowball-common的问题里,是关于slf4j的MDC问题,若继续探究请进入:APM 模块

日志收集记录系统

根据InheritableThreadLocal在线程池中上下文传递的问题,知道InheritableThreadLocal这个类完成了上下文传递,但是由于池的存在,当线程被下一次重复使用的时候,由于Map的内容没有更新,出现了traceId的重复(也就是不对应)

Session级Cache、应用容器给下层SDK传递信息

这两个不属于本次所讨论内容。。。

 

TTL在日志收集系统的两种实现

  • log4j2-ttl-thread-context-map
    pom.xml

    <``dependency``>``    ``<``groupId``>com.alibaba</``groupId``>``    ``<``artifactId``>log4j2-ttl-thread-context-map</``artifactId``>``    ``<``version``>1.3.0</``version``>``    ``<``scope``>runtime</``scope``>``</``dependency``>

    只需将此依赖项添加到您的项目中即可激活Log4j2 TTL ThreadContextMap

    通过log4j2.threadContextMap=com.alibaba.ttl.log4j2.TtlThreadContextMap的方式将MDC的adapter实现进行替换

  •  logback-mdc-ttl
    pom.xml

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

    在Java的启动参数加上:

    -Xbootclasspath``/a``:``/path/to/transmittable-thread-local-2``.x.x.jar``-javaagent:``/path/to/transmittable-thread-local-2``.x.x.jar

    在logback配置文件中增加TtlMdcListener

    <?``xml version``=``"1.0" encoding``=``"UTF-8"``?>``<``configuration >``<!-- ...(略) -->``<``contextListener class``=``"com.ofpay.logback.TtlMdcListener"``/>``<!--例子: %X{uuid} 支持在跨线程池时传递-->``<``property scope``=``"context" name``=``"APP_PATTERN"``value``=``'%d{yyyy-MM-dd HH:mm:ss.SSS}|%X{uuid}|%level|%M|%C\:%L|%thread|%replace(%.-2000msg){"(\r|\n)","\t"}|"%.-2000ex{full}"%n'``/>``</``configuration``>

    通过将contextListener的方式,将MDC的adapter实现进行替换

TTL在snowball-common中的应用

snowball-common在webFilter中将应用接收的请求,采用Twitter的finagle框架自带的TraceID放入到MDC中,而且整个采用了slf4j的日志框架

 

因此,就基于logback-mdc-ttl的方案对snowball-common进行升级

pom.xml引入

<``dependency``>``    ``<``groupId``>com.ofpay</``groupId``>``    ``<``artifactId``>logback-mdc-ttl</``artifactId``>``    ``<``version``>1.0.2</``version``>``    ``<``exclusions``>``        ``<``exclusion``>``            ``<``groupId``>com.alibaba</``groupId``>``            ``<``artifactId``>transmittable-thread-local</``artifactId``>``        ``</``exclusion``>``    ``</``exclusions``>``</``dependency``>``<``dependency``>``    ``<``groupId``>com.alibaba</``groupId``>``    ``<``artifactId``>transmittable-thread-local</``artifactId``>``    ``<``version``>2.11.0</``version``>``</``dependency``>

至此,升级工作完毕

 

应用升级snowball-common

pom.xml

在snowball-common的version版本>-5.0.3

<``dependency``>``    ``<``groupId``>com.xueqiu.snowball</``groupId``>``    ``<``artifactId``>snowball-common</``artifactId``>``    ``<!-- version 大于等于5.0.3 -->``    ``<``version``>5.0.3</``version``>``</``dependency``>

pom引入agent的依赖包

<``dependency``>``    ``<``groupId``>com.alibaba</``groupId``>``    ``<``artifactId``>transmittable-thread-local</``artifactId``>``    ``<``version``>2.11.0</``version``>``</``dependency``>

start_server.sh

在启动脚本上添加JVM参数,将agent的路径换成自己的

-javaagent:..``/lib/transmittable-thread-local-2``.11.0.jar``-Xbootclasspath``/a``:..``/lib/transmittable-thread-local/2``.11.0``/transmittable-thread-local-2``.11.0.jar

logback.xml

在logback的配置问价中添加contextListener参数

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

以上升级工作完毕

 

性能评估:

github.com/alibaba/tra…

 

参考资料:

github.com/oldratlee/l…

github.com/ofpay/logba…

github.com/alibaba/tra…

www.infoq.cn/article/jav…

lovestblog.cn/blog/2014/0…