[ 
https://issues.apache.org/jira/browse/KAFKA-18046?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Anthony Maire updated KAFKA-18046:
----------------------------------
    Description: 
This is pretty similar to KAFKA-15141 that impacted server side : when using 
log4j2 as SLF4J implementation, LoggerFactory.getLogger() is a pretty costly 
operation that use StackWalker under the hood and can have a performance impact 
in hot code paths

The attached CPU profiling shows that getLogger() is responsible for more than 
20% of CPU usage in KafkaConsumer.poll(), because 
org.apache.kafka.clients.consumer.internals.CompletedFetch constructor uses 
org.apache.kafka.common.utils.LogContext.logger(Class<?>) which calls 
LoggerFactory.getLogger().

I can provide a PR for this, but there are 2 possible implementations :
- don't change LogContext API, but keep a static cache of loggers inside it 
(using ConcurrentHashMap.computeIfAbsent() ) : it will cache logger for all 
classes using LogContext, including cold paths. The memory retention induced by 
it was very low in my tests as loggers are already referenced in Log4J internal 
maps. A heap dump showed an additionnal 848 bytes retained by the cache for 24 
entries in my tests

- If we want to only do this on the hot code paths and make sure we avoid any 
memory retention, then we should add a new method LogContext.logger(Logger) 
that would wrap a static logger instantiated in the relevant classes.

My preference would be to do a global fix by using the first approach, but I 
wanted to ask there first before proviing a PR if I missed a scenario when it 
could create a undesirable significant memory retention

  was:
This is pretty similar to KAFKA-15141 that impacted server side : when using 
log4j2 as SLF4J implementation, LoggerFactory.getLogger() is a pretty costly 
operation that use StackWalker under the hood and can have a performance impact 
in hot code paths

 

The attached CPU profiling shows that getLogger() is responsible for more than 
20% of CPU usage in KafkaConsumer.poll(), because 
org.apache.kafka.clients.consumer.internals.CompletedFetch constructor uses 
org.apache.kafka.common.utils.LogContext.logger(Class<?>) which calls 
LoggerFactory.getLogger().

I can provide a PR for this, but there are 2 possible implementations :
- don't change LogContext API, but keep a static cache of loggers inside it 
(using ConcurrentHashMap.computeIfAbsent() ) : it will cache logger for all 
classes using LogContext, including cold paths. The memory retention induced by 
it was very low in my tests as loggers are already referenced in Log4J internal 
maps. A heap dump showed an additionnal 848 bytes retained by the cache for 24 
entries in my tests

 

- If we want to only do this on the hot code paths and make sure we avoid any 
memory retention, then we should add a new method LogContext.logger(Logger) 
that would wrap a static logger instantiated in the relevant classes.

My preference would be to do a global fix by using the first approach, but I 
wanted to ask there first before proviing a PR if I missed a scenario when it 
could create a undesirable significant memory retention


> High CPU usage when using Log4j2
> --------------------------------
>
>                 Key: KAFKA-18046
>                 URL: https://issues.apache.org/jira/browse/KAFKA-18046
>             Project: Kafka
>          Issue Type: Improvement
>          Components: consumer
>    Affects Versions: 3.6.1, 3.8.1
>            Reporter: Anthony Maire
>            Priority: Major
>         Attachments: kafka_consumer_getLogger.png
>
>
> This is pretty similar to KAFKA-15141 that impacted server side : when using 
> log4j2 as SLF4J implementation, LoggerFactory.getLogger() is a pretty costly 
> operation that use StackWalker under the hood and can have a performance 
> impact in hot code paths
> The attached CPU profiling shows that getLogger() is responsible for more 
> than 20% of CPU usage in KafkaConsumer.poll(), because 
> org.apache.kafka.clients.consumer.internals.CompletedFetch constructor uses 
> org.apache.kafka.common.utils.LogContext.logger(Class<?>) which calls 
> LoggerFactory.getLogger().
> I can provide a PR for this, but there are 2 possible implementations :
> - don't change LogContext API, but keep a static cache of loggers inside it 
> (using ConcurrentHashMap.computeIfAbsent() ) : it will cache logger for all 
> classes using LogContext, including cold paths. The memory retention induced 
> by it was very low in my tests as loggers are already referenced in Log4J 
> internal maps. A heap dump showed an additionnal 848 bytes retained by the 
> cache for 24 entries in my tests
> - If we want to only do this on the hot code paths and make sure we avoid any 
> memory retention, then we should add a new method LogContext.logger(Logger) 
> that would wrap a static logger instantiated in the relevant classes.
> My preference would be to do a global fix by using the first approach, but I 
> wanted to ask there first before proviing a PR if I missed a scenario when it 
> could create a undesirable significant memory retention



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to