From 5f2e44bb11cf0923959d73bae11259b3f7715103 Mon Sep 17 00:00:00 2001 From: pricelees Date: Tue, 14 Oct 2025 00:38:46 +0000 Subject: [PATCH] =?UTF-8?q?[#60]=20Trace=20Context=EC=9D=98=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94=20=EC=98=A4=EB=A5=98=EB=A1=9C=20=EB=B0=9C?= =?UTF-8?q?=EC=83=9D=ED=95=98=EB=8A=94=20OOM=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20(#63)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 관련 이슈 및 PR **PR과 관련된 이슈 번호** - #60 ## ✨ 작업 내용 - JVM Heapdump 분석 결과 Opentelemetry의 Context가 과도한 메모리를 사용하고 있었음.(Retain 925MB / 파드 메모리 할당 Limit 2GB 중) - 원인은, 하나의 요청이 끝날 때 Trace Context가 초기화 되지 않았고, 동일한 Tomcat 스레드에 서로 다른 HTTP 요청의 SPAN이 계속 쌓인 것. - Slow-query 를 기록하기 위한 Datasource-Proxy와 충돌이 그 이유였고, 슬로우쿼리 기록은 필요하기에 CurrentTraceContext를 이용하여 필터의 Finally 과정에서 컨텍스트를 정리하도록 수정 ## 🧪 테스트 - JVM의 Old, Survivor Space에서의 메모리 사용량 감소 확인 - 동일한 환경 테스트에서 OOM 발생하지 않음. ## 📚 참고 자료 및 기타 Reviewed-on: https://gitea.pricelees.me/pricelees/roomescape-refactored/pulls/63 Co-authored-by: pricelees Co-committed-by: pricelees --- .../com/sangdol/common/web/config/WebLoggingConfig.kt | 6 ++++-- .../sangdol/common/web/servlet/HttpRequestLoggingFilter.kt | 7 ++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/common/web/src/main/kotlin/com/sangdol/common/web/config/WebLoggingConfig.kt b/common/web/src/main/kotlin/com/sangdol/common/web/config/WebLoggingConfig.kt index 9539657e..be3aef54 100644 --- a/common/web/src/main/kotlin/com/sangdol/common/web/config/WebLoggingConfig.kt +++ b/common/web/src/main/kotlin/com/sangdol/common/web/config/WebLoggingConfig.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.sangdol.common.web.asepct.ControllerLoggingAspect import com.sangdol.common.web.servlet.HttpRequestLoggingFilter import com.sangdol.common.web.support.log.WebLogMessageConverter +import io.micrometer.tracing.CurrentTraceContext import org.springframework.boot.web.servlet.FilterRegistrationBean import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -17,9 +18,10 @@ class WebLoggingConfig { @Bean @DependsOn(value = ["webLogMessageConverter"]) fun filterRegistrationBean( - webLogMessageConverter: WebLogMessageConverter + webLogMessageConverter: WebLogMessageConverter, + currentTraceContext: CurrentTraceContext ): FilterRegistrationBean { - val filter = HttpRequestLoggingFilter(webLogMessageConverter) + val filter = HttpRequestLoggingFilter(webLogMessageConverter, currentTraceContext) return FilterRegistrationBean(filter) .apply { this.order = Ordered.HIGHEST_PRECEDENCE + 2 } diff --git a/common/web/src/main/kotlin/com/sangdol/common/web/servlet/HttpRequestLoggingFilter.kt b/common/web/src/main/kotlin/com/sangdol/common/web/servlet/HttpRequestLoggingFilter.kt index a5e45a5d..e0a22dd2 100644 --- a/common/web/src/main/kotlin/com/sangdol/common/web/servlet/HttpRequestLoggingFilter.kt +++ b/common/web/src/main/kotlin/com/sangdol/common/web/servlet/HttpRequestLoggingFilter.kt @@ -5,6 +5,7 @@ import com.sangdol.common.utils.MdcStartTimeUtil import com.sangdol.common.web.support.log.WebLogMessageConverter import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging +import io.micrometer.tracing.CurrentTraceContext import jakarta.servlet.FilterChain import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse @@ -15,7 +16,8 @@ import org.springframework.web.util.ContentCachingResponseWrapper private val log: KLogger = KotlinLogging.logger {} class HttpRequestLoggingFilter( - private val messageConverter: WebLogMessageConverter + private val messageConverter: WebLogMessageConverter, + private val currentTraceContext: CurrentTraceContext ) : OncePerRequestFilter() { override fun doFilterInternal( request: HttpServletRequest, @@ -32,9 +34,12 @@ class HttpRequestLoggingFilter( try { filterChain.doFilter(cachedRequest, cachedResponse) cachedResponse.copyBodyToResponse() + } catch (e: Exception) { + throw e } finally { MdcStartTimeUtil.clear() MdcPrincipalIdUtil.clear() + currentTraceContext.maybeScope(null) } } }