web-dev-qa-db-ja.com

Log4j:マルチスレッド呼び出し用に同期されていますか?

システムのストレステストを行っているときに気付いた興味深い問題が発生しています。ロギングにlog4j(JBOSS内)を非常に頻繁に使用しています。これは私たちが行ったいくつかのロギングの素朴な例です

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

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

ここで気付いた興味深い点は、この関数に対して100スレッドを起動した場合です。 Log.info()呼び出しはスレッドごとにブロックされています。つまり、スレッド2はthread1が「Log.info」呼び出しを終了するのを待っています。スレッド100の場合;かなり長い間待つことになります。ネイティブファイルロガーを使用しています。

これは既知の問題ですか?

17
shergill

Log4Jを同期する必要があります。そうしないと、ファイルにインターリーブされたログメッセージと文字化けしたログメッセージが表示されます。ただし、少なくともログバックでは、ログメッセージ全体ではなく、アペンダーのみが同期されます(したがって、有効なログレベル、ログメッセージなどの計算はマルチスレッド化されます)。

ただし、同期が削除された場合でも、I/Oは本質的にシングルスレッドであるため、ボトルネックになります。したがって、Log4Jではなくファイルアクセスが遅いため、ログの量を減らすことを検討してください。

AsyncAppender を使用して、ログメッセージを単一の異なるスレッドでキューに入れることもできます。

12

はい、log4jはマルチスレッド同期を使用します。そして、時には完全ではありません。

複雑なtoString()メソッドを使用すると、log4jロックの競合やデッドロックによってパフォーマンスが低下することがありました。

https://issues.Apache.org/bugzilla/show_bug.cgi?id=24159 および https://issues.Apache.org/bugzilla/show_bug.cgi?id=たとえば、41214#c38

私の別の答えの詳細: log4jのプロダクション設定ファイル?

これがログバックが存在する理由の1つであり、JBoss AS6以降カスタムログマネージャーに切り替えていると思います。

2
Vadzim

あなたが望むかもしれないのは非同期ロギングです、それを達成する方法についてはこの記事を見てください:

log4jを使用した非同期ロギング

また、適切なログレベルの使用を検討してください。 _entered..._およびexi(s)ted...ステートメントは通常TRACEレベルでログに記録する必要があります。これは、デバッグ時に便利です(次に、configurelog4jをTRACEレベルでログに記録するように設定します。上手)。本番環境では、log4jにレベルINFOまたはDEBUGからのみログを記録するように指示して、不要なログアクションを回避することができます。

Log4jのパフォーマンスに関する次の質問も参照してください。

log4jパフォーマンス

2
The Nail

他の人はすでにあなたに代替案を提案しています、私はソースコードを掘り下げてきました、そして確かに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);
    }
}
1
Tudor