OutputStreamManager.write上的Log4j2线程阻塞



背景我正在使用带有同步根和异步记录器的log4j2(2.12.1(。Lmax环形缓冲区大小默认为256*1024。控制台中的追加程序。我正在使用JSON布局记录MapMessage。我的日志消息的平均大小约为100字节。

有了以上细节,我注意到上有几个线程被阻塞

"http-nio-8080-exec-172" #451
Thread State: BLOCKED (on object monitor) owned by "http-nio-8080-exec-148" Id=429
at org.apache.logging.log4j.core.appender.OutputStreamManager.write(OutputStreamManager.java:231)
- blocked on <0x000000003eb936ae> (a org.apache.logging.log4j.core.appender.OutputStreamManager)
at org.apache.logging.log4j.core.appender.OutputStreamManager.writeBytes(OutputStreamManager.java:206)
at org.apache.logging.log4j.core.layout.AbstractLayout.encode(AbstractLayout.java:211)
at org.apache.logging.log4j.core.layout.AbstractLayout.encode(AbstractLayout.java:37)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:197)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:190)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:181)
at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:156)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:129)
at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:120)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:84)
at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:543)
at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:502)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:485)
at org.apache.logging.log4j.core.config.LoggerConfig.logParent(LoggerConfig.java:534)
at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:504)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:485)
at org.apache.logging.log4j.core.async.AsyncLoggerConfig.log(AsyncLoggerConfig.java:121)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:460)
at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:82)
at org.apache.logging.log4j.core.Logger.log(Logger.java:162)
at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2190)
at org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2144)
at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2127)
at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1828)
at org.apache.logging.log4j.spi.AbstractLogger.info(AbstractLogger.java:1282)

我的问题是…

  1. 环形缓冲区是否很快就满了,这会对主线程造成背压(在我的案例中,servlet容器线程是http-nio-8080-exec-148(?堆转储显示RingBuffer总是占用7MB(测试之前和之后(
  2. 若环形缓冲区很快就满了,我该如何增加它的大小?或者可能是丢弃事件
  3. 看看Log42的性能报告,我知道不建议使用Console appender,但我在这里真的别无选择。有更好的追加器可以写入STDOUT吗

欢迎任何建议或想法。

该锁用于防止多个线程同时写入同一个OutputStream,因为这可能会导致数据混合。尽管不能保证,但许多OutputStream实现无论如何都会锁定要写入的调用——因此,即使锁定被移除,它也只会在OutputStream实施中阻塞。

这显然是因为使用的OutputStream正在从其他线程写入数据。此线程并不表示环形缓冲区已满,但可能是其他线程因此而被阻塞。我不清楚为什么必须向控制台写入,但登录云提供了更多数据,说明为什么不应该这样做,以及在云环境中运行时有什么替代方案。

更新:在查看了完整的线程转储之后,我有一些观察结果:

  1. 有许多线程在com.xxxx.apie.library.InternalRequest.execute(InternalRequest.java:273)处等待。这些线程似乎在等待在另一个线程上执行工作,但从线程转储中还不清楚这到底是什么
  2. 有几个线程记录到被阻止的输出流。这些调用源自几个类中的各个点,但都是在信息级别进行日志记录的
  3. 您正在使用JsonLayout
  4. 您没有发布Log4j配置,但在上面的堆栈跟踪中,您可以看到AsyncLoggerConfig正在调用LoggerConfig的日志方法。在查看AsyncLogger中的代码时,可能会发现您配置了一个没有Appender引用的AsyncLoggers,因此Logger正在委派给其父级,该父级不是异步记录器,因此日志事件甚至没有排队到环形缓冲区,而是直接从应用程序线程记录

最重要的是,您正在同步记录到OutputStream(可能是控制台(,而线程正在阻止它,因为I/O速度很慢。

最新更新