Toss Tech BLog

Reactor Netty Memory Leak 이슈 탐방기

thumbnail

Reactor Netty Memory Leak 이슈 탐방기

Spring Cloud Gateway에서 발생한 Reactor Netty 메모리 누수 문제를 해결하기 위해, 요청 바디를 캐시한 후 자원을 제대로 해제하지 않아 발생한 것을 확인하였습니다. 문제를 해결하기 위해, 요청 바디를 가져올 때 reference counter를 증가시키고, 캐시된 바디를 잃어버렸을 때 reference counter를 내리는 로직을 수정하였습니다. 이슈를 확인한 후, 관련하여 Spring Cloud Gateway Github에서 수정 사항을 찾을 수 있었습니다.

WebClient Memory Leak 이슈 파악하기

서비스에서 발생한 WebClient의 메모리 누수 문제의 원인을 찾아보았습니다. 문제는 토스 뱅크에서 담당 서버 개발자분과 뱅크 서버 플랫폼 팀에서 확인해주셨습니다. 버그는 요청이 취소되었을 때 Mono를 정리할 때 응답 바디를 명시적으로 해제하는 코드가 없었던 것이었습니다. 코드를 수정하여 응답 바디를 해제하도록 하여 이슈를 해결하였습니다.

Native Memory Leak의 원인 깊이 이해하기

Heap 영역이 아닌 Native 메모리가 증가하는 이유를 이해하기 위해, Reactor Netty의 요청과 응답 바디 처리 방식에 관계가 있음을 발견하였습니다. Reactor Netty를 사용하는 프로젝트에서 요청과 응답 바디를 제대로 처리하지 않으면 Heap 영역이 아닌 Native 영역에서 메모리 누수가 발생합니다. 이러한 문제의 원인은 Buffer를 할당 받을 때 초기 reference counter 값이 1이며, 동일한 Buffer를 다른 곳에서 사용하는 경우 reference counter가 증가하는 것입니다. Spring Cloud Gateway의 메모리 누수 문제는 요청 바디를 가져올 때 reference counter가 증가하지만, 저장된 바디를 잃어버리면서 reference counter를 내리지 못하여 발생했습니다. WebClient의 경우는 요청이 취소되어 응답 바디에 대한 메모리 해제가 되지 못해 메모리 누수가 발생했습니다. 이를 해결하기 위해, Reactor Netty 기반 프로젝트에서는 Buffer를 올바르게 소멸하거나 해제하는지 꼼꼼하게 확인해야 합니다.