인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

dlsrksrhk님의 프로필 이미지

작성한 질문수

개발자에게 필요한 로그 관리

표준출력(println)과 로깅 프레임워크 성능 차이

표준출력보다 Slf4J가 느릴 때

작성

·

99

1

저는 컴터 사양이 꽤나 좋아서 인지? 항상 표준출력이 더 빠르더군요.

알아보니 로깅 프레임워크가 느린 이유에는 대략 이런 이유들이 있네요.

  • 로그 출력에 여러 과정을 거침. Logger → Appender → Encoder → Layout → OutputStream

  • 레벨 설정에 의한 필터링

  • 로그 포맷팅 처리

분명 표준출력이 synchronized에 의해서 멀티 스레드 환경에서 취약한건 맞으나 현재 테스트에서는 그 부분이 로깅 프레임워크의 처리 과정보다는 빨랐던 것 같습니다.

테스트 환경 변경

그래서 테스트 환경을 바꿔서 테스트 해보았습니다.

멀티스레드 환경. 스레드 10개. 각 스레드별 100000번 출력

package kr.co.shortenurlservice.log;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class SoutVsAsyncLoggingTest {

    private static final int THREAD_COUNT = 10;
    private static final int LOG_COUNT = 100_000;

    public static void main(String[] args) throws InterruptedException {
        // 1. System.out.println() 테스트
        long sysoutTime = runTest(i ->
            System.out.println("[SYSOUT][" + Thread.currentThread().getName() + "] " + i)
        );

        // 2. log.info() (AsyncAppender + Console) 테스트
        long asyncLogTime = runTest(i ->
            log.info("[LOGGER][{}] {}", Thread.currentThread().getName(), i)
        );

        // 결과 출력
        Thread.sleep(5000);
        System.out.printf("System.out: %,d ms%n", sysoutTime);
        System.out.printf("Async log : %,d ms%n", asyncLogTime);
    }

    private static long runTest(StringConsumer task) throws InterruptedException {
        long start = System.currentTimeMillis();

        ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
        CountDownLatch latch = new CountDownLatch(THREAD_COUNT);

        for (int t = 0; t < THREAD_COUNT; t++) {
            executor.submit(() -> {
                for (int i = 0; i < LOG_COUNT; i++) {
                    task.accept(i);
                }
                latch.countDown();
            });
        }

        latch.await();
        executor.shutdown();

        long end = System.currentTimeMillis();
        return end - start;
    }

    @FunctionalInterface
    interface StringConsumer {
        void accept(int value);
    }
}

또한 test/resources/logback.xml 설정으로 포맷을 날짜 같은것 제외하고 표준출력과 똑같이 맞춰주고 AsyncAppender를 통해 멀티 스레드 환경에서 차별점이 있도록 비동기 Appender를 추가해줌.

<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%msg%n</pattern>
        </encoder>
    </appender>

    <appender name="ASYNC_CONSOLE" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="CONSOLE"/>
        <queueSize>10240</queueSize>
    </appender>

    <root level="info">
        <appender-ref ref="ASYNC_CONSOLE"/>
    </root>
</configuration>

이렇게 하니까 표준출력보다 빠르더군요.

꼭 성능문제뿐 아니라 로그 관리체계 자체가 로깅 프레임워크가 넘사이기 때문에 안쓸 비교불가겠지만..

성능적으로 보더라도 실무 환경이라면 메시지 출력 전후로 비즈니스 로직들이 있기 때문에 임계영역을 통해 스레드를 대시시키는 표준출력을 사용하는것보다는 로깅 프레임워크가 더욱 성능적으로 이점이 있을 것 같습니다.

답변 2

0

이준형(Foo)님의 프로필 이미지
이준형(Foo)
지식공유자

dlsrksrhk님 강의 내용에서 더 심화된 분석 글 감사합니다!

AsyncAppender에 대한 내용도 언급할까 하다가 환경에 따라 차이가 나지 않을 수도 있어서 다루지 않았는데, 테스트 해주신 것처럼 표준출력이 오히려 빠른 경우 AsyncAppender로 변경했을 때 표준출력보다도 빨라질 수 있습니다.

마지막에 이야기 해주신 것처럼, 성능 문제를 떠나서 로그 관리 차원에서 로깅 프레임워크 활용하는게 좋고, 실무 환경이라면 표준 출력이 경쟁적인 상태가 될 거라 로깅 프레임워크를 활용하는게 더 높은 성능을 보일겁니다. 😀

남겨주신 내용은 제가 강의 노트란에도 추가해두겠습니다~

감사합니다!!

0

인프런 AI 인턴님의 프로필 이미지

안녕하세요, 인프런 AI 인턴입니다. dlsrksrhk님.

로그 출력 테스트 중 Slf4J(로깅 프레임워크)와 표준 출력(System.out.println)의 성능 차이를 평가하신 결과에 대한 설명을 감사합니다. 이와 관련하여 비슷한 주제로 논의된 기존의 질문과 답변을 참고하시면 좋을 것 같습니다.

표준 출력과 Slf4J 로깅 프레임워크 비교

  • 이 질문에서는 비슷하게 Slf4J와 표준 출력의 성능 테스트를 다루며, 로깅 프레임워크를 사용할 경우의 장점과 단점을 서술하고 있습니다.

요약

  1. 표준 출력과 Slf4J의 성능 비교:

    • 표준 출력(System.out.println)은 synchronized 키워드로 인해 멀티스레드 환경에서는 잠재적 성능 병목을 초래할 수 있습니다.
    • 로깅 프레임워크(Slf4J 등)는 비동기 로깅을 지원하여 멀티스레드 환경에서의 성능을 개선할 수 있습니다.
  2. Slf4J를 사용하는 이유:

    • 로그 관리의 유연성: 다양한 로그 수준(Level), 로그 포맷 설정, 그리고 파일 및 콘솔 출력 등의 다양한 Appender를 설정할 수 있습니다.
    • 비동기 처리의 이점: 특히 멀티스레드 환경에서 비동기적으로 로그를 처리하여 시스템의 퍼포먼스를 향상시킬 수 있습니다.
  3. AsyncAppender 추가 설정의 효과:

    • AsyncAppender을 활용하여 로깅 작업을 비동기로 수행하면 로그 출력이 스레드의 주요 작업에서 비동시적으로 빠져나가게 되어 성능에 긍정적인 영향을 미칠 수 있습니다.

위 답변이 도움이 되셨기를 바라며, 로깅 프레임워크의 성능 및 설정에 대한 이해를 도울 수 있기를 바랍니다. 추가적으로 궁금한 점이 있으시면, 질문을 이어서 남겨주세요.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 계속 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.