question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Performance degradation when using JDK 11 and log4j2

See original GitHub issue

Hi folks,

Thanks for this great lib. I found an issue and would like to share it with you.

With JDK 11 and multi-release open, the log4j2 lib will use the implementations with the Java9+ specific classes. This can cause a great performance degradation (roughly 30% in our service) because Armeria tries to create a new Logger on every request which will cause a slow deep stack walk initiated by log4j2.

The typical stack trace is like this:

"armeria-common-worker-nio-2-3" #35 daemon prio=5 os_prio=31 cpu=5581.88ms elapsed=20.00s tid=0x00007fee5d0ea000 nid=0x7d03 runnable  [0x0000700010ab0000]
   java.lang.Thread.State: RUNNABLE
        at java.lang.StackStreamFactory$AbstractStackWalker.fetchStackFrames(java.base@11.0.2/Native Method)
        at java.lang.StackStreamFactory$AbstractStackWalker.fetchStackFrames(java.base@11.0.2/StackStreamFactory.java:386)
        at java.lang.StackStreamFactory$AbstractStackWalker.getNextBatch(java.base@11.0.2/StackStreamFactory.java:322)
        at java.lang.StackStreamFactory$AbstractStackWalker.peekFrame(java.base@11.0.2/StackStreamFactory.java:263)
        at java.lang.StackStreamFactory$AbstractStackWalker.hasNext(java.base@11.0.2/StackStreamFactory.java:351)
        at java.lang.StackStreamFactory$StackFrameTraverser.tryAdvance(java.base@11.0.2/StackStreamFactory.java:593)
        at java.util.stream.ReferencePipeline.forEachWithCancel(java.base@11.0.2/ReferencePipeline.java:127)
        at java.util.stream.AbstractPipeline.copyIntoWithCancel(java.base@11.0.2/AbstractPipeline.java:502)
        at java.util.stream.AbstractPipeline.copyInto(java.base@11.0.2/AbstractPipeline.java:488)
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(java.base@11.0.2/AbstractPipeline.java:474)
        at java.util.stream.FindOps$FindOp.evaluateSequential(java.base@11.0.2/FindOps.java:150)
        at java.util.stream.AbstractPipeline.evaluate(java.base@11.0.2/AbstractPipeline.java:234)
        at java.util.stream.ReferencePipeline.findFirst(java.base@11.0.2/ReferencePipeline.java:543)
        at org.apache.logging.log4j.util.StackLocator.lambda$getCallerClass$6(StackLocator.java:59)
        at org.apache.logging.log4j.util.StackLocator$$Lambda$10/0x0000000800063040.apply(Unknown Source)
        at java.lang.StackStreamFactory$StackFrameTraverser.consumeFrames(java.base@11.0.2/StackStreamFactory.java:534)
        at java.lang.StackStreamFactory$AbstractStackWalker.doStackWalk(java.base@11.0.2/StackStreamFactory.java:306)
        at java.lang.StackStreamFactory$AbstractStackWalker.callStackWalk(java.base@11.0.2/Native Method)
        at java.lang.StackStreamFactory$AbstractStackWalker.beginStackWalk(java.base@11.0.2/StackStreamFactory.java:370)
        at java.lang.StackStreamFactory$AbstractStackWalker.walk(java.base@11.0.2/StackStreamFactory.java:243)
        at java.lang.StackWalker.walk(java.base@11.0.2/StackWalker.java:498)
        at org.apache.logging.log4j.util.StackLocator.getCallerClass(StackLocator.java:58)
        at org.apache.logging.log4j.util.StackLocatorUtil.getCallerClass(StackLocatorUtil.java:65)
        at org.apache.logging.slf4j.Log4jLoggerFactory.getContext(Log4jLoggerFactory.java:45)
        at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:48)
        at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:30)
        at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:358)
        at com.linecorp.armeria.server.DefaultServiceRequestContext.newLogger(DefaultServiceRequestContext.java:208)
        at com.linecorp.armeria.server.DefaultServiceRequestContext.<init>(DefaultServiceRequestContext.java:194)
        at com.linecorp.armeria.server.DefaultServiceRequestContext.<init>(DefaultServiceRequestContext.java:127)
        at com.linecorp.armeria.server.HttpServerHandler.handleRequest(HttpServerHandler.java:351)
        at com.linecorp.armeria.server.HttpServerHandler.channelRead(HttpServerHandler.java:240)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)

Under performance testing, using jstack we can see lots of threads named with pattern armeria-common-worker-nio-* has a similar stack trace likes above. To alleviate this situation, we need to remove the multi-release mark like this to revert log4j2 to the implementation compatible with JDK8. This will lead log4j2 to use sun.reflect.Reflection.getCallerClass and leave a WARNING log as follows when the service is start. But the performance is way better than with the log4j2 for the JDK11.

WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance.

My testing environment is:

  • armeria: 0.97.0
  • log4j-slf4j-impl: 2.12.1
  • log4j-core: 2.12.1
  • slf4j: 1.7.29
  • jdk: 11.0.2
  • OS: mac 10.15.1

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:6

github_iconTop GitHub Comments

2reactions
anuraagacommented, Dec 10, 2019

Thanks for the report this seems like a big issue.

ServiceRequestContext.logger() has been deprecated for almost forever - time to remove it? @trustin @minwoox @ikhoon

https://github.com/line/armeria/blob/master/core/src/main/java/com/linecorp/armeria/server/ServiceRequestContext.java#L260

0reactions
trustincommented, Dec 31, 2019

Fixed via #2341

Read more comments on GitHub >

github_iconTop Results From Across the Web

log4j2 performance issues with Java 11-Apache Mail Archives
I am working on moving my Java application development from Java 8 and JavaFX 8 to Java 11 and JavaFX 11, and am...
Read more >
Re: log4j2 performance issues with Java 11 - The Mail Archive
Yes, the network lookup thing is a startup bug that only happens once per JVM startup (or at least until its internal DNS...
Read more >
Is log4j2 compatible with Java 11? - Stack Overflow
I tried to run my project on the latest Java 11. Everything works, except the specific file logger. Logging works fine on previous...
Read more >
Performance degradation when using JDK 11 and log4j2
Performance degradation when using JDK 11 and log4j2. line. 09 December 2019 Posted by ylgrgyq. Hi folks,. Thanks for this great lib.
Read more >
Log4j2 Isn't Killing Java | Foojay.io Today
JDK Flight Recorder is a performance analysis tool included in modern OpenJDK distributions that can also produce some security information with ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found