一、背景

最近几个业务遇到服务假死的情况,通过排查,我们发现是因为业务在线上使用了日志框架的ConsoleAppender所致

请尊重作者劳动成果,转载请标明原文链接:https://www.cnblogs.com/waterystone/p/11170540.html

二、排查过程

2.1 被block线程的堆栈

我们跟进后通过jsack把线程的堆栈打出来,发现大量线程被同一把monitor锁block住了(at org.apache.logging.log4j.core.layout.TextEncoderHelper.copyDataToDestination),其中一个完整的线程堆栈如下:

通过堆栈我们可以看到,线程执行到TextEncoderHelper.copyDataToDestination()时,需要获取一把OutputStreamManager对象的锁,但这个锁被其他线程锁住了。源码如下(注:OutputStreamManager是ByteBufferDestination的子类):

2.2 获取锁的线程的堆栈

那么这把锁被哪个线程锁住了呢?这个线程又在干什么呢?进一步排查,获取该锁的线程堆栈如下:

我们发现,业务线程在使用ConsoleAppender打印日志时,需要同步获取到OutputStreamManager对象的monitor锁,然后同步调用PrintStream.write() → BufferedOutputStream.write() → FileOutputStream.write() ,接着flush(),等写到Console成功后,才会释放锁,而其他需要获取该锁的业务线程在此期间只能阻塞等待。其调用时序如下:

2.3 console日志性能分析

从前两步我们看到,在打印console日志时,需要先获取到OutputStreamManager对象的monitor锁,然后同步调用PrintStream.write() → BufferedOutputStream.write() → FileOutputStream.write() ,接着flush(),等写到Console成功后,才会释放锁。这期间其他打印console日志的线程都要被该monitor锁block住

那么我们就有理由怀疑同步块中调用这些write()操作效率太低,从而导致大量其他业务线程被block住。通过官网查证,打印console日志,效率还真不是一般的低!!!如下所示:

三、AsyncLogger

从以上分析我们可以看到,业务通过同步Logger使用ConsoleAppender时会阻塞业务线程其实通过同步Logger使用RollingRandomAccessFileAppender也会阻塞业务线程,只不过其同步块的处理效率更高些而已。那么有没有其他更高效的解决方案呢?有!AsyncLogger!!!

log4j2框架通过引入高性能环形消息队列框架Disruptor,将打印日志操作异步化,解除对业务线程的同步阻塞,极大加快业务线程的响应时间

详细信息参考官网:https://logging.apache.org/log4j/2.x/manual/async.html

其工作时序如下:

从上图可以看出,业务线程在使用AsyncLogger打印日志时,将日志消息放到disruptor的环形队列后即返回,这里也不会涉及到锁的同步竞争,极大加快了业务线程的响应时间。Disruptor会有一个专门的线程池来负责监听环形队列的消息事件,并将其落地。

AsyncLogger具有超强的性能,官方数据如下:


3.1 如何接入

AsyncLogger这么好用,如何接入呢?

1)在log4j2框架下,额外引入disruptor。

<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.2</version>
</dependency>

2)log4j2.xml配置成如下方式:

<Loggers>
<!-- 将spring日志设置成info -->
<AsyncLogger name="org.springframework" level="ERROR" includeLocation="true" /> <asyncRoot level="INFO" includeLocation="true">
<AppenderRef ref="INFO" />
<AppenderRef ref="WARN" />
<AppenderRef ref="ERROR" />
</asyncRoot>
</Loggers>

四、总结

  • 线上业务,严禁使用ConsoleAppender
  • 线上业务,强烈推荐AsyncLogger
  • 线上业务,可以使用同步Logger,但不推荐。以性能较高的RollingRandomAccessFileAppender为例,其在打印日志时同样也需要获取RollingRandomAccessFileManager对象的monitor锁,只不过该同步块中的处理效率较高,不像OutputStreamManager锁块那么低效而已。

看到这里,你还有什么理由使用ConsoleAppender呢???还有什么理由不使用AsyncLogger呢?!

log4j输出到控制台的性能问题的更多相关文章

  1. []jnhs]日志套件log4j输出到控制台和文件

    log4j的xml配置文件改为 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j: ...

  2. spring mvc 引入log4日记记录maven工程 slf4j和log4j输出到控制台配合使用log4j不输出到文件

    https://blog.csdn.net/qq_27093465/article/details/62928590 使用slf4j的优点: 提供带参数的日志输出方法(SLF4J 1.7及以后版本). ...

  3. log4j中Spring控制台输出Debug级信息过多解决方法

    log4j中Spring控制台输出Debug级信息过多解决方法 >>>>>>>>>>>>>>>>> ...

  4. log4j输出日志到文件

    输出端Appender Appender用来指定日志信息输出到哪个地方,可以同时指定多个输出目的地.Log4j允许将信息输出到许多不同的输出设备中,一个log信息输出目的地就叫做一个Appender. ...

  5. Log4j 输出的日志中时间比系统时间少了8小时的解决方法,log4j日志文件重复输出

    1. 第一个问题:时间少了8小时 Log4j 输出的日志中,时间比系统时间少了8小时,但是 eclipse 控制台输出的日志的时间却是对的. log4j配置如下: #all logger output ...

  6. log4j输出日志乱码(转)

    log4j日志文件乱码问题的解决方法 log4j日志文件中文乱码处理方法 log4j 控制台和文件输出乱码问题解决 写在前面,第三篇文章中将原因解释的最清楚,为什么设置为UTF-8或者GBK就生效了, ...

  7. 使用log4j输出日志

    今天在倒腾log4j,其实蛮简单的. 一.首先是下载log4j的jar包. 二.将下载的jar包添加到web工程的WEB-INF/lib包下 三.在src/config包下新建log4j.proper ...

  8. 在intelllij中debug的时候使用log4j输出

    一般在本地调试的时候,在控制台打印输出都会使用system.out.print,但是在线上运行的时候一般都是使用log4j进行日志输出. 那么在编写代码的时候,又不想写两份,直接写LOG是常规动作. ...

  9. 日志输出最不重要的就是控制台输出,控制台输出就是system.out而已

    1.日志输出最不重要的就是控制台输出,控制台输出就是system.out而已 2.所以日志输出时候会存在一个Bug就是:stdout要配置在日志输出的最前面,因为stdout控制台输出,最不重要,如果 ...

随机推荐

  1. java为什么要用类型擦除实现泛型?--c++,java,c# 的泛型是如何实现的

    所以总结一下c++,java,c#的泛型.c++的泛型在编译时完全展开,类型精度高,共享代码差.java的泛型使用类型擦出,仅在编译时做类型检查,在运行时擦出,共享代码好,但是类型精度不行.c#的泛型 ...

  2. A Pattern Language for Parallel Application Programming

    A Pattern Language for Parallel Application Programming Berna L. Massingill, Timothy G. Mattson, Bev ...

  3. 读书会荐书 - 关于Ada Lovelacer的书

    今天很感谢Weny组织了这期读书会, 我受益良多. 会上我推荐了<中的精神>, 但是会后想起有更好的书. 就是关于Ada Lovelace的书. 先简单介绍一下Ada Lovelacer. ...

  4. C# 方法默认访问级别 : private C# 类默认访问级别 : internal

    C# 方法默认访问级别 : private C# 类默认访问级别 : internalpublic:访问不受限制.protected:访问仅限于包含类或从包含类派生的类型.Internal:访问仅限于 ...

  5. NeatUpload .NetFromWork4.0 config配置

    NeatUpload使用---config配置(可进行大文件传输) configuration> 下增加: <configSections> <sectionGroup nam ...

  6. Winform的控件以及DataGridView的一般使用

    先上学习测试的一些截图 1:获取多个控件上面的值(checkbox,combobox,textbox,radiobutton) 2:获取到选择行的主键ID的value,方便我们进一步CURD 3:获取 ...

  7. Java生鲜电商平台-redis缓存在商品中的设计与架构

    Java生鲜电商平台-redis缓存在商品中的设计与架构 说明:Java开源生鲜电商平台-redis缓存在商品中的设计与架构. 1. 各种计数,商品维度计数和用户维度计数 说起电商,肯定离不开商品,而 ...

  8. excel转pdf,itextpdf转换excel

    最近项目有需求,需要把excel转pdf.由于时间比较急,所以在github上找了一个转换的.最终没用上,但还是踩坑了一波. 踩坑一: 首先,这个是导出的流之间会互相影响,因为流读取过,导致导出的ex ...

  9. 【入门篇】前端框架Vue.js知识介绍

    一.Vue.js介绍 1.什么是MVVM? MVVM(Model-View-ViewModel)是一种软件架构设计模式,它源于MVC(Model-View-Controller)模式,它是一种思想,一 ...

  10. shuffle调优

    目录 一.概述 二.shuffle的定义 三.ShuffleMananger发展概述 四.HashShuffleManager的运行原理 4.1 未经优化的HashShuffleManager 4.2 ...