Reactor Netty Memory Leak 이슈 탐방기
김성현 · 토스 · 토스 기술 블로그
소개
Spring Cloud Gateway와 Spring WebClient를 이용하면서 발생한 Memory Leak 이슈의 발생 원인과 해결 과정을 소개합니다.
AI 핵심 요약
Spring Cloud Gateway와 Spring WebClient를 사용하는 서비스에서 컨테이너 RSS가 계속 증가하고 Netty의 ByteBuf 누수 경고가 발생해 원인을 추적했습니다. Gateway에서는 CacheRequestBody 필터가 캐싱한 요청 바디를 해제하지 않는 버그를 확인해 수정 사항이 반영된 버전으로 해결했습니다. WebClient에서는 connection pool의 연결 해제를 막으려고 Mono.cache()를 적용했지만, 취소 시 응답 바디 해제 로직도 건너뛰어 누수가 발생했으며 취소 여부를 추적해 바디를 명시적으로 release하도록 바꿨습니다. 두 사례 모두 Reactor Netty의 Direct Buffer가 native memory에 할당되고 reference count로 관리되므로, 요청·응답 바디의 사용과 해제 경로를 꼼꼼히 확인해야 한다는 점을 보여줍니다.
- 컨테이너 OOM을 조사할 때 JVM Heap 지표만 보지 말고 RSS와 Netty Direct Buffer 사용량도 함께 확인하세요.
- Reactor Netty의 ByteBuf는 reference count가 0이 되어야 풀로 반환되므로, 사용이 끝난 버퍼는 반드시 release해야 합니다.
- Mono.cache()는 취소 신호를 원본 요청에 전달하지 않으므로, 취소 시 응답 바디를 명시적으로 정리하는 처리가 필요할 수 있습니다.
- Spring Cloud Gateway의 CacheRequestBody 필터는 사용 중인 버전의 메모리 해제 관련 수정 사항을 확인하세요.
비슷한 학습 자료
토스ㅣSLASH 22 - Java Native Memory Leak 원인을 찾아서
SLASH · YouTube
Spark Connect on Kubernetes #1: 견고한 Spark Connect 만들기
박지원 · 토스 기술 블로그
프로젝트 전체에서 사용되는 패키지, 어떻게 마이그레이션 할까?
김덕원 · 토스 기술 블로그
웹에서 복잡한 퍼널 쉽게 관리하기
임재후/최수민 · 토스 기술 블로그
토스는 Gateway 이렇게 씁니다
최준우 · 토스 기술 블로그
99%가 모른다는 DB Connection 누수 문제
김동호 · 컬리 기술 블로그