티스토리 뷰
1. Logback AsyncAppender의 동작 방식과 neverBlock 설정의 필요성
[ Logback AsyncAppender의 동작 방식과 neverBlock 설정 ]
AsyncAppender은 Logback에서 지원하는 Appender 중 하나로, 로그 출력이 애플리케이션의 주요 흐름을 지연시키지 않도록 비동기 형태로 로그 처리를 진행한다. AsyncAppender은 내부적으로 생산자-소비자(Producer-Consumer) 기반으로 동작하며, 이를 위해 내부에 큐(BlockingQueue)가 존재한다. 로그를 찍는 코드를 실행하면 생산자는 로그 이벤트를 큐에 쌓고, 별도의 작업 스레드인 소비자는 큐에서 로그 이벤트를 꺼내서 이를 처리한다.

AsyncAppender는 큐에 로그를 먼저 적재하고, 실제 처리는 비동기로 수행되기 때문에 애플리케이션의 성능(특히 TPS)을 향상시킬 수 있다. 하지만 트래픽이 급증하여 쌓아야 하는 로그가 많아진 경우, 소비자가 큐의 로그 이벤트를 처리하는 속도보다 생산자가 로그 이벤트를 큐에 넣는 속도가 훨씬 빨라서, 큐(BlockingQueue)의 용량에 의한 문제가 생길 수 있다. 먼저, AsyncAppender의 로그 적재 로직(append)을 보면 다음과 같다. 참고로 다음의 코드는 AsyncAppender의 부모 클래스인 AsyncAppenderBase에서 확인할 수 있다.

이러한 로직을 정리하면 다음과 같다고 볼 수 있다.
- 남은 큐의 크기가 일정 수준(20%) 이하이며, INFO 보다 낮은 수준인 경우 버림
- 그렇지 않은 경우 neverBlock 설정에 따름
- 큐에 offer함, 큐가 가득 찬 경우에 넣지 않고 false를 반환하고 버려짐
- 큐에 put함, 큐가 가득 찬 경우에 대기 후 넣음
위의 로직을 통해 살펴볼 수 있듯이, 큐의 여유 공간이 20%보다 많다면 모든 로그를 적재한다. 하지만 트래픽이 많아 로그 이벤트 큐의 여유 공간이 20% 이하라면 먼저 INFO 레벨 이하의 로그를 버리게 된다. 하지만 WARN 또는 ERROR 레벨의 로그라면, neverBlock 설정에 따라 처리가 달라진다. neverBlock이 false라면, 큐(BlockingQueue)에 데이터를 저장할 때까지 대기하게 되는데, 이는 애플리케이션의 스레드를 블로킹 및 중단시켜 요청 처리에 영향을 줄 수 있다. 반면에 neverBlock 값을 true로 설정하면, 큐가 꽉 찬 상태에서는 메시지를 버리도록 하여 서비스의 안정성을 높일 필요가 있다. 물론 이렇게 하면 로그가 유실된다는 문제가 생기지만, 애플리케이션 스레드가 처리를 중단하여 대규모 장애로 이어지는 것보다는 훨씬 안정적이라고 볼 수 있다.
따라서 Logback과 Logback의 AsyncAppender를 사용하는 경우 neverBlock을 true로 설정하여, 로그 적재에 의해 애플리케이션의 처리가 중단되지 않도록 이러한 설정에 대해 유의하고 챙겨주도록 하자.
참고 자료
'Server' 카테고리의 다른 글
| [Kafka] 올바른 카프카 컨슈머(KafkaConsumer) 설정 가이드와 내부 동작 분석 (8) | 2025.06.24 |
|---|---|
| [Server] COW(CopyOnWrite) 기법과 이를 활용하는 자바와 레디스의 예시들(COW on Java and Redis) (2) | 2025.06.10 |
| [Server] K6 부하 테스트 시나리오 작성하고 결과 지표 분석하기(K6 Load Testing) (2) | 2025.04.01 |
| [LLM] MCP(Model Context Protocol)에 대하여 알아보고 IntelliJ와 Claude를 MCP로 연동하기 (11) | 2025.03.25 |
| [Redis] Lettuce를 사용하는 경우에 MGET 동작 방식과 해시태그(HashTag) (4) | 2025.03.18 |