공부목표
리눅스에서 소켓 누수 문제에 대해 공부하고 재현합니다.
- 어떻게 소켓 누수 문제를 확인할 수 있는지?
- 소켓 누수가 계속 발생하면 어떤 문제가 발생할 수 있는지?
소켓 누수란
소켓 누수는 종료되어야 할 소켓이 닫히지 않고 계속 남아있는 현상입니다. 사용한 소켓을 close하지 않으면 발생합니다.
소켓과 fd의 관계
리눅스는 소켓을 생성할 때 fd(파일 디스크립터)를 할당합니다. 리눅스에서 소켓은 파일로 관리되기 때문입니다.
/proc/{pid}/fd에서 프로세스가 사용 중인 fd를 확인할 수 있습니다. socket 문자열이 보이는 fd가 소켓입니다.
ls -l /proc/{pid}/fd
fd 고갈과 시스템 장애
fd는 무한히 만들 수 없어 소켓 누수가 계속되면 fd를 고갈시킵니다. 이 영향으로 소켓, 파일 등 입출력 리소스를 생성하지 못하고 Too many open files 에러가 발생합니다.

소켓 누수를 방치하면 벌어지는 일
소켓 누수가 지속되면 fd가 고갈되면서 리눅스에서 실행 중인 모든 프로세스가 영향을 받습니다. 더 나아가서 시스템 전체에 영향을 미쳐 서비스 장애가 발생할 수 있습니다.
예를 들어 Java 프로세스에서는 누수된 소켓을 정리하기 위해 GC(가비지 컬렉터)가 빈번하게 실행됩니다. CPU, 메모리등 시스템 리소스 사용률이 함께 올라갑니다. 리소스 사용률이 100%에 육박하면 서버는 불안정상태가 됩니다.
이 영향으로 서버가 원래 처리해야할 일을 못하고 일들이 남은 서버로 전달되게 됩니다. 남은 서버들이 부하를 견디지 못하면 서비스 장애가 시작됩니다. http프로토콜 관점에서는 남은 서버에서 부하가 발생하면 클라이언트에서 connection timeout이 발생하고 재시도를 실행하는 retry storm현상이 발생합니다.

테스트
mariadb-java-client 2.7.2에서 SocketException 발생 시 소켓을 close하지 않는 버그를 이용해 소켓 누수를 재현했습니다.
실습 환경
- MariaDB 10.11 컨테이너
- Spring Boot 2.7.18 앱 컨테이너 (커넥션 풀 없이 Raw JDBC 직접 사용, fd를 64로 제한)
- mariadb-java-client 2.7.2 (예외 시 소켓을 닫지 않는 드라이버)
- socketTimeout=3000 (3초 제한)
결과
k6로 부하를 발생시키고 Prometheus, Grafana로 모니터링했습니다. 부하가 발생하자 fd 사용률이 거의 100%에 도달했습니다.

Spring Boot 컨테이너를 확인하면 fd가 대량으로 쌓여 있었습니다.

소켓 상태가 전부 ESTABLISHED였습니다. 닫혀야 할 소켓이 닫히지 않고 남아있는 것입니다.

fd가 고갈되면서 Too many open files 에러가 발생했습니다.

Too many open files 에러는 시간이 갈수록 증가했습니다.

JVM에서는 GC 발생 빈도가 증가했습니다. 제가 JVM GC 동작을 잘 모르는데, 누수된 소켓을 정리하기 위해 GC가 계속 실행되는 것 같습니다.

'전공영역 공부 기록' 카테고리의 다른 글
| Java (pod)가 부팅 직후 느린 이유: Lazy Loading과 JVM warm up (0) | 2026.04.12 |
|---|---|
| claude code로 wordpress 테마를 변경하고 페이지 렌더링 속도를 98% 단축한 후기 (0) | 2026.04.10 |
| Access Key 없이 IAM user가 AWS CLI 쓰는 방법(aws login) (0) | 2026.03.29 |
| custom EKS AMI 만들기 - Managed Node Group과 Karpenter 설정 차이 (0) | 2026.03.29 |
| Cache-Control, 브라우저부터 CDN까지 (0) | 2026.03.22 |