Log4j:多线程调用是否同步?

发布于 2025-01-06 17:34:39 字数 361 浏览 3 评论 0原文

我们在对系统进行压力测试时注意到了一个有趣的问题。我们在日志记录中大量使用 log4j(在 JBOSS 中)。这是我们已有的一些日志记录的简单示例。

void someFunction()
{
Log.info("entered some function");
...

Log.info("existed some function");
}

现在我们注意到有趣的事情是,如果我们针对此函数启动 100 个线程; Log.info() 调用每个线程都会阻塞。这意味着线程 2 正在等待线程 1 完成“Log.info”调用。如果是线程 100;它最终等待了相当长的时间。我们正在使用本机文件记录器。

这是一个已知问题吗?

We are running into an interesting issue that we noticed while doing stress testing of our system. We are using log4j (in JBOSS) very heavily for our logging. Here is a naive example of some logging we ave

void someFunction()
{
Log.info("entered some function");
...

Log.info("existed some function");
}

Now the interesting thing we noticed is that if we launch 100 threads against this function; the Log.info() calls is blocking per thread.. meaning thread 2 is waiting for thread1 to finish the "Log.info" call. In case of Thread 100; it ends up waiting quite a long time.. We are using a native file logger.

Is this a known issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

反差帅 2025-01-13 17:34:39

Log4J 必须同步,否则您会在文件中看到交错和乱码的日志消息。但至少在 Logback 中,仅同步附加程序,而不是整个日志消息(因此计算有效日志级别、日志消息等是多线程的)。

然而,即使删除了同步,I/O 也将成为瓶颈,因为它本质上是单线程的。因此,请考虑减少日志记录量,因为慢的是文件访问,而不是 Log4J。

您可能还对 AsyncAppender 感兴趣在单个不同的线程中对日志消息进行排队。

Log4J has to be synchronized, otherwise you would see interleaved and garbled log messages in your file. But at least in Logback only appenders are synchronized, not the whole logging message (so computing effective log level, log message, etc. is multi-threaded).

However even if synchronization was removed, I/O would be the bottleneck since it is inherently single-threaded. Thus consider reducing the amount of logging, since it is the file access that is slow, not Log4J.

You may also be interested in AsyncAppender to queue logging messages in a single, different thread.

怂人 2025-01-13 17:34:39

您可能想要的是异步日志记录,请参阅这篇文章了解如何实现这一点:

使用 log4j 进行异步日志记录

另外,请考虑使用正确的日志级别。 entered...exi(s)ted... 语句通常应记录在 TRACE 级别,这在调试时可能很方便(然后将配置 log4j 设置为在 TRACE 级别进行日志记录)。在生产环境中,您可能希望告诉 log4j 仅从 INFODEBUG 级别进行日志记录,从而避免不必要的日志操作。

另请参阅有关 log4j 性能的问题:

log4j 性能

What you might want is asynchronous logging, see this article on how to achieve that:

Asynchronous logging with log4j

Also, consider using the right log levels. The entered... and exi(s)ted... statements should typically be logged at TRACE level, which might be handy when debugging (then set configure log4j to log at TRACE level as well). In a production setting you might want to tell log4j to log only from level INFO or DEBUG, thus avoiding unnecessary log actions.

See also this question on the performance of log4j:

log4j performance

梨涡少年 2025-01-13 17:34:39

是的,log4j使用多线程同步。有时并不完美。

我们遇到了由于 log4j 锁争用而导致的性能下降,甚至在使用复杂的 toString() 方法时出现死锁。

请参阅 https://issues.apache.org/bugzilla/show_bug.cgi?id =24159https://issues.apache.org/bugzilla/show_bug.cgi?id=41214#c38

更详细的内容可以参考我的另一个回答:
我想这

是原因之一自 JBoss AS 6 以来,logback 的存在以及切换到自定义日志管理器。

Yes, log4j uses multithread synchronization. And not perfectly, sometimes.

We experienced some performance degradation caused by contention for log4j locks and even deadlocks with use of the complex toString() method.

See https://issues.apache.org/bugzilla/show_bug.cgi?id=24159 and https://issues.apache.org/bugzilla/show_bug.cgi?id=41214#c38, for example.

More details in my other answer:
Production settings file for log4j?

I guess this is one of the reasons of the logback existence and the switch to the custom logmanager since JBoss AS 6.

迷鸟归林 2025-01-13 17:34:39

其他人已经向您建议了替代方案,我一直在挖掘源代码,确实有一个 synchronized 部分:

public void info(Object message) {
    if(repository.isDisabled(Level.INFO_INT))
       return;
    if(Level.INFO.isGreaterOrEqual(this.getEffectiveLevel()))
       forcedLog(FQCN, Level.INFO, message, null);
}

...

protected void forcedLog(String fqcn, Priority level, Object message, Throwable t) {
    callAppenders(new LoggingEvent(fqcn, this, level, message, t));
}

...

public void callAppenders(LoggingEvent event) {
    int writes = 0;

    for(Category c = this; c != null; c=c.parent) {
        // Protected against simultaneous call to addAppender, removeAppender,...
        synchronized(c) {
            if(c.aai != null) {
                writes += c.aai.appendLoopOnAppenders(event);
            }
            if(!c.additive) {
                break;
            }
        }
    }

    if(writes == 0) {
        repository.emitNoAppenderWarning(this);
    }
}

Others have already suggested you alternatives, I've been digging through the source code and indeed there is a synchronized section:

public void info(Object message) {
    if(repository.isDisabled(Level.INFO_INT))
       return;
    if(Level.INFO.isGreaterOrEqual(this.getEffectiveLevel()))
       forcedLog(FQCN, Level.INFO, message, null);
}

...

protected void forcedLog(String fqcn, Priority level, Object message, Throwable t) {
    callAppenders(new LoggingEvent(fqcn, this, level, message, t));
}

...

public void callAppenders(LoggingEvent event) {
    int writes = 0;

    for(Category c = this; c != null; c=c.parent) {
        // Protected against simultaneous call to addAppender, removeAppender,...
        synchronized(c) {
            if(c.aai != null) {
                writes += c.aai.appendLoopOnAppenders(event);
            }
            if(!c.additive) {
                break;
            }
        }
    }

    if(writes == 0) {
        repository.emitNoAppenderWarning(this);
    }
}
佞臣 2025-01-13 17:34:39

同意之前的回答。在任何应用程序中,首要的性能改进步骤之一就是降低日志级别并使其转储更少的日志。应用程序开发人员应该努力使用正确的日志记录级别。由于 I/O 和同步,日志记录对性能有巨大影响,尤其是当记录器对象是静态的并在各个线程之间共享时。

Agree with previous answers. One of the first performance improvement steps in any application is to reduce the log level and have it dump less logs. Application developers should be diligent in using the right logging levels. Logging has a huge impact on performance because of I/O as well as synchronization especially when logger objects are static and shared among various threads.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文