Linux Socket Leak(Socket 누수)의 원인과 해결 방법

Linux 서버를 운영하다 보면 서비스가 오랫동안 실행된 후 Too many open files, EMFILE, Cannot assign requested address, Connection refused 등의 오류가 발생하는 경우가 있습니다. 이러한 문제의 대표적인 원인 중 하나가 바로 Socket Leak(Socket 누수)입니다.

Socket Leak은 프로그램이 더 이상 사용하지 않는 소켓(Socket)을 정상적으로 닫지 않아 파일 디스크립터(File Descriptor)가 계속 증가하는 현상을 말합니다. 시간이 지날수록 시스템 자원이 소모되며, 결국 새로운 네트워크 연결을 생성하지 못하는 상황까지 이어질 수 있습니다.

이번 글에서는 Socket Leak의 원인과 확인 방법, 해결 방법을 실무 중심으로 자세히 알아보겠습니다.

Socket Leak이란?

Socket은 네트워크 통신을 위한 파일 디스크립터(FD)의 한 종류입니다.

애플리케이션은 다음과 같은 과정을 거쳐 통신합니다.

socket()

↓

connect() 또는 accept()

↓

read()/write()

↓

close()

정상적인 프로그램은 통신이 끝난 후 반드시 close()를 호출해야 합니다.

하지만 close()가 실행되지 않으면 Socket이 계속 남아 있게 되고 이를 Socket Leak이라고 합니다.

Socket Leak이 발생하는 주요 원인

대표적인 원인은 다음과 같습니다.

  • close() 호출 누락
  • 예외(Exception) 처리 오류
  • Socket Pool 관리 실패
  • Connection Pool 버그
  • CLOSE_WAIT 증가
  • 멀티스레드 동기화 문제
  • 비정상 종료
  • 프로그램 버그
  • 라이브러리 버그
  • 장시간 실행되는 서비스

실무에서는 예외 발생 시 close()가 호출되지 않는 경우가 가장 흔한 원인입니다.

1. 현재 열린 Socket 확인하기

현재 열린 Socket을 확인합니다.

ss -tan

또는

netstat -tan

연결 개수가 시간이 지날수록 계속 증가하는지 확인합니다.

2. 프로세스별 Socket 확인하기

PID가 1234인 경우

lsof -p 1234

Socket만 확인하려면

lsof -p 1234 | grep socket

Socket 개수가 지속적으로 증가하는지 확인합니다.

3. FD 개수 확인하기

현재 열린 FD 개수를 확인합니다.

ls /proc/1234/fd | wc -l

시간이 지나도 FD가 줄어들지 않는다면 누수를 의심할 수 있습니다.

4. CLOSE_WAIT 확인하기

Socket Leak은 CLOSE_WAIT 증가와 함께 나타나는 경우가 많습니다.

ss -ant | grep CLOSE-WAIT

개수 확인

ss -ant | grep CLOSE-WAIT | wc -l

CLOSE_WAIT가 계속 증가한다면 애플리케이션이 Socket을 닫지 못하고 있을 가능성이 높습니다.

5. strace로 close() 확인하기

close() 호출 여부를 확인합니다.

strace -p PID

또는

strace -e close -p PID

close() 호출이 거의 없고 read(), write()만 반복된다면 누수를 의심할 수 있습니다.

6. 애플리케이션 로그 확인하기

로그에서 다음과 같은 오류를 확인합니다.

Too many open files

EMFILE

Broken pipe

Connection reset by peer

서비스 로그도 함께 확인합니다.

journalctl -u nginx

또는

journalctl -u tomcat

7. FD 사용량 확인하기

시스템 전체 FD 사용량을 확인합니다.

cat /proc/sys/fs/file-nr

현재 프로세스의 제한도 확인합니다.

ulimit -n

FD 사용량이 지속적으로 증가한다면 원인을 분석해야 합니다.

8. Connection Pool 확인하기

DB 또는 HTTP Connection Pool 설정을 확인합니다.

예를 들어 다음 항목을 점검합니다.

  • maxConnections
  • maxPoolSize
  • idleTimeout
  • maxLifetime

Connection Pool에서 사용 후 반환(Return)이 정상적으로 이루어지는지 확인합니다.

9. 메모리 사용량 확인하기

Socket Leak은 메모리 증가와 함께 발생하는 경우도 많습니다.

top

또는

htop

메모리 사용량과 FD 증가가 함께 발생하는지 확인합니다.

10. 코드 점검하기

예외가 발생해도 반드시 Socket을 닫도록 구현해야 합니다.

예시(Java)

Socket socket = null;

try {
    socket = new Socket(host, port);

    // 작업 수행

} finally {
    if (socket != null) {
        socket.close();
    }
}

Java에서는 try-with-resources, Python에서는 with, Go에서는 defer, C++에서는 RAII 등을 활용하면 Socket Leak을 예방하는 데 도움이 됩니다.

Socket Leak 점검 순서

실무에서는 다음 순서대로 확인하는 것이 좋습니다.

  1. Socket 개수 확인
  2. FD 개수 확인
  3. CLOSE_WAIT 확인
  4. 프로세스 확인
  5. close() 호출 확인
  6. 애플리케이션 로그 확인
  7. FD 사용량 확인
  8. Connection Pool 확인
  9. 메모리 사용량 확인
  10. 코드 분석

Socket Leak 사용 시 주의사항

다음 사항을 고려해야 합니다.

  • Limit만 늘려서는 해결되지 않는다.
  • CLOSE_WAIT도 함께 분석한다.
  • Connection Pool 설정을 확인한다.
  • 예외 처리 시 close()를 반드시 호출한다.
  • 장시간 실행되는 서비스는 주기적으로 모니터링한다.
  • FD 증가 추이를 함께 확인한다.

Socket Leak은 운영 초기에 잘 드러나지 않지만, 장시간 서비스가 실행될수록 큰 장애로 이어질 수 있습니다.

Socket Leak과 Memory Leak의 차이

항목Socket LeakMemory Leak
누수 대상Socket(FD)메모리
주요 증상Too many open filesOut of Memory
확인 명령어lsof, sstop, pmap
주요 원인close() 누락메모리 해제 누락

두 문제는 함께 발생하는 경우도 있지만 서로 다른 자원 누수이므로 각각 분석해야 합니다.

자주 묻는 질문

Socket Leak은 왜 장시간 실행 후 발생하나요?

Socket이 하나씩 해제되지 않고 계속 누적되기 때문입니다. 초기에는 문제가 없어 보이지만 시간이 지날수록 FD가 모두 소진되어 장애가 발생합니다.

ulimit 값을 늘리면 해결되나요?

아닙니다. FD 제한을 높이는 것은 일시적인 대응일 뿐이며, Socket을 닫지 않는 코드가 그대로라면 결국 같은 문제가 반복됩니다.

CLOSE_WAIT가 많으면 반드시 Socket Leak인가요?

반드시 그렇지는 않습니다. 하지만 CLOSE_WAIT가 지속적으로 증가하고 FD 수도 함께 증가한다면 Socket Leak 가능성이 매우 높습니다.

마무리

Socket Leak은 네트워크 프로그래밍에서 가장 자주 발생하는 자원 누수 중 하나입니다. ss, lsof, strace, /proc, journalctl 등을 활용하면 원인을 빠르게 분석할 수 있으며, close() 호출을 보장하는 코드 작성과 Connection Pool 관리, 지속적인 FD 모니터링을 통해 안정적인 Linux 서버 운영이 가능합니다.

댓글 남기기