1. 증상

  • API 서버에서 OutOfMemoryError: unable to create new native thread 발생
  • 해당 서버에서의 장애로 인해 서비스 접속 간헐적 에러 발생

2. 선조치

  • 장애 복구를 위해 배포를 시도했으나, SFTP 접근 중 secure 로그상에 do_exec_no_pty: fork: Resource temporarily unavailable 오류 발생
  • 톰캣 강제 종료 후 커널 파라미터 (open files, max user processes) 조정 및 배포 진행정상화

3. Root Cause 분석

(1) 주요 확인 사항

  1. OOM 발생 로그 분석 결과, 신규 쓰레드 생성이 불가능한 상태 (추가로 secure로그를 통해 파일 디스크립터 부족 가능성 시사)
  2. 동일한 환경의 이중화 서버 중 API 1번에서만 문제 발생

(2) 상세 분석

  • OOM 발생 후 JMX Exporter를 통한 모니터링을 시작한 결과, api 1에서만 
    쓰레드 개수가 비정상적으로 증가하는 현상 확인
  • jstack을 이용한 분석 결과, 아래와 같이 쓰레드풀에서 WAITING 상태의 쓰레드가 지속적으로 생성됨
"pool-xxxx-thread-1" #xxxx prio=5 os_prio=0 cpu=0.12ms elapsed=567.11s tid=0x00007f23e5048000 nid=0x740f9 waiting on condition  [0x00007f215cd92000]
   java.lang.Thread.State: WAITING (parking)
       at jdk.internal.misc.Unsafe.park(java.base@xx.x.xx/Native Method)
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ중략ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

 

(3) 원인 분석

  • API 소스 내 Java 쓰레드 생성 관련 코드를 점검한 결과,
    ExecutorService executor = Executors.newFixedThreadPool(5);
    특정소스의 위 코드에서 생성된 쓰레드풀을 명시적으로 종료 (shutdown)하지 않는 문제를 확인
  • 추가로 개발 담당자와의 프로세스 검토 결과, 로드밸런싱이 되는 서비스이기에, 1번 서버에 요청이 집중되는 현상의 원인 파악이 확인 필요
    •  VIP의 L4 로드밸런싱 설정이 Hash 기반 → 동일 클라이언트 IP에서 들어오는 요청이 특정 서버에 집중될 가능성이 있음
    •  이를 검증하기 위해 L4 로드밸런싱 메트릭을 Round Robin 방식으로 변경 후 테스트 진행
    •  그 결과, 1번과 2번 서버 모두에서 쓰레드풀 WAITING 증가 현상 확인 → 원인 파악 완료

(4) 주말간 OOM 발생 원인

  • 쓰레드풀 생성 후 회수가 이루어지지 않아 ulimitmax user processes 임계치 도달
  • 임의의 환경(max user processes 최소값)에서 테스트 코드 실행 시 동일한 OOM 발생 재현 확인

4. 조치 사항

  1. 소스 수정
  2. 커널 파라미터 조정
  3. 어플리케이션 모니터링 강화

5. 결론:

  • 쓰레드풀 미회수로 인한 max user processes 임계 도달이 OOM 발생의 직접적인 원인, 이를 해결하기 위해 소스 수정 및 커널파라미터 튜닝 진행

+ Recent posts