log4j输出到控制台的性能问题
一、背景
最近几个业务遇到服务假死的情况,通过排查,我们发现是因为业务在线上使用了日志框架的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输出到控制台的性能问题的更多相关文章
- []jnhs]日志套件log4j输出到控制台和文件
log4j的xml配置文件改为 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j: ...
- spring mvc 引入log4日记记录maven工程 slf4j和log4j输出到控制台配合使用log4j不输出到文件
https://blog.csdn.net/qq_27093465/article/details/62928590 使用slf4j的优点: 提供带参数的日志输出方法(SLF4J 1.7及以后版本). ...
- log4j中Spring控制台输出Debug级信息过多解决方法
log4j中Spring控制台输出Debug级信息过多解决方法 >>>>>>>>>>>>>>>>> ...
- log4j输出日志到文件
输出端Appender Appender用来指定日志信息输出到哪个地方,可以同时指定多个输出目的地.Log4j允许将信息输出到许多不同的输出设备中,一个log信息输出目的地就叫做一个Appender. ...
- Log4j 输出的日志中时间比系统时间少了8小时的解决方法,log4j日志文件重复输出
1. 第一个问题:时间少了8小时 Log4j 输出的日志中,时间比系统时间少了8小时,但是 eclipse 控制台输出的日志的时间却是对的. log4j配置如下: #all logger output ...
- log4j输出日志乱码(转)
log4j日志文件乱码问题的解决方法 log4j日志文件中文乱码处理方法 log4j 控制台和文件输出乱码问题解决 写在前面,第三篇文章中将原因解释的最清楚,为什么设置为UTF-8或者GBK就生效了, ...
- 使用log4j输出日志
今天在倒腾log4j,其实蛮简单的. 一.首先是下载log4j的jar包. 二.将下载的jar包添加到web工程的WEB-INF/lib包下 三.在src/config包下新建log4j.proper ...
- 在intelllij中debug的时候使用log4j输出
一般在本地调试的时候,在控制台打印输出都会使用system.out.print,但是在线上运行的时候一般都是使用log4j进行日志输出. 那么在编写代码的时候,又不想写两份,直接写LOG是常规动作. ...
- 日志输出最不重要的就是控制台输出,控制台输出就是system.out而已
1.日志输出最不重要的就是控制台输出,控制台输出就是system.out而已 2.所以日志输出时候会存在一个Bug就是:stdout要配置在日志输出的最前面,因为stdout控制台输出,最不重要,如果 ...
随机推荐
- C++:class
class 类是C++的一个重要概念,也是面向对象的一个重要内容.类的行为类似结构体,但功能比结构体的更强大.类是定义该类对象的一个模板,它告诉我们,一个类应该具有什么内容. 声明.定义 类用关键字c ...
- CSS选择器[attribute | = value] 和 [attribute ^ = value]的区别
前言 首先你需要知道[attribute | = value] 和 [attribute ^ = value] 分别是什么? ①:[attribute | = value] ②:[attribute ...
- 将服务器时间类型改为UTC(0000)
方法一: # timedatectl set-timezone UTC # timedatectl set-time "YYYY-MM-DD HH:MM:SS" # time ...
- centos6利用cgroup冻结一个程序运行
操作步骤: 安装cgroup服务 yum install libcgroup 配置cgroup vim /etc/cgconfig.conf group stopit{ #添加一个cgroup组 fr ...
- Oracle 原生驱动带来的精度问题的分析与解决
问题 Oracle 官方提供了 dotnet core 驱动,但我们在使用中遇到了精度问题. 复现 以下代码运行数学运算 1/3,无论是 OracleCommand.ExecuteScalar() 还 ...
- kali渗透综合靶机(十七)--HackInOS靶机
kali渗透综合靶机(十七)--HackInOS靶机 靶机下载地址:https://www.vulnhub.com/hackinos/HackInOS.ova 一.主机发现 1.netdiscover ...
- C++回调,函数指针
想要理解回调机制,先要理解函数指针 函数指针 函数指针指向的是函数而非对象,和其他指针一样,函数指针指向某种特定的类型 函数的类型由他的返回类型和参数类型共同决定,与函数名无关,如: bool len ...
- Xamarin移动开发备忘
vs2017下: 1.debug用于本地生成和调试,release用于发布.区别主要在于: 安卓项目的生成选项属性中,开发者模式release是不勾的,而且高级里的cpu不同(debug是x86,re ...
- Unable to connect to web server 'IIS Express'(无法连接到Web服务器“IIS Express”)的解决方式-Jexus Manager
在运行微软示例工程eShopOnWeb时候, 在经过一段时间再运行启动报Error "Unable to connect to web server 'IIS Express'" ...
- Tp5.1开发初入门
今天需要给金融部门那边做一个信用卡的推广页面,他们系统是用PHP的tp框架做的.我记得最早做tp还是2的时候,和现在的5.1相差太大了,中间开发的时候,还是遇到了点问题.所以,把今天的问题记录下,作个 ...