一、背景

最近几个业务遇到服务假死的情况,通过排查,我们发现是因为业务在线上使用了日志框架的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. 微信小程序开发语音识别文字教程

    微信小程序开发语音识别文字教程 现在后台 添加插件 微信同声传译 然后app.json 加入插件 "plugins": { "WechatSI": { &quo ...

  2. 一、Spring注解之@ComponentScan

    Spring注解之@ComponentScan [1]@ComponentScan注解是什么 @ComponentScan主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bea ...

  3. com.alibaba.fastjson.JSONObject之对象与JSON转换方法

    com.alibaba.fastjson.JSONObject时经常会用到它的转换方法,包括Java对象转成JSON串.JSON对象,JSON串转成java对象.JSON对象,JSON对象转换Java ...

  4. Log4Net记录日志(mvc)

    转自:http://blog.csdn.net/zhoufoxcn/article/details/2220533 感谢:柄棋先生 第一步:下载Log4Net 下载地址:http://logging. ...

  5. 关于前端ajax请求url为何添加一个随机数

    一.起因 我在做爬虫的时候发现很多网站上都在url上加一个随机数或者时间戳一开始我以为是啥加密后面发现其实他在后台解析的时候也不需要不排除有些网站他反爬就需要一个时间戳,那他加个随机数是做啥子 二.查 ...

  6. STorM32 BGC三轴增稳云台驱动下载

    STorM32 BGC是一种硬件开源.软件闭源的三轴稳定云台控制项目.云台在我们生活中是越来越常见,我们手机拍照用的手持云台,无人机上挂载摄像机的机载隔振云台.我们在电影<流浪地球>里面那 ...

  7. Mybatis插入实体类字段为关键字解决方案

    1. Mybatis插入实体类字段为关键字解决方案 1.1. 前言 可能你插入字段为关键字时报如下错误,且字段名不适合改变 You have an error in your SQL syntax; ...

  8. EFLAGS寄存器(标志寄存器)

    这篇文章不是从0开始的,前面还有一些汇编基础指令以及进制,我都没写,时间问题,还是今天空闲,我才想补一下博文,后面我陆续会把前面知识点渐渐补上.我不会重0基础讲起,中间会以.汇编.C.C++交叉的形式 ...

  9. win10无法在桌面右键快捷打开个性化设置、显示设置,在任务栏右键无法快捷打开任务栏设置

    Win+R,输入regedit,定位到HKEY_CURRENT_USER\Software\Classes\ 找到列表中的ms-settings 将其删除即可解决! 转自百度知道

  10. mysql数据库之忘记root密码

    1.  vi /etc/my.cnf,在[mysqld]中添加 skip-grant-tables 例如: [mysqld] skip-grant-tables datadir=/var/lib/my ...