장애 대응 실무 가이드 · Part 8

자원 고갈

평소 멀쩡하다가 어느 순간 무너지는 자원 문제 다루기

작성 기준2026년 7월

이 파트에서 다루는 내용

애플리케이션 자원커넥션 풀스레드 풀파일 디스크립터디스크와 로그한계값 파악
01

애플리케이션 자원은 OS 자원과 다릅니다

CPU, 메모리, 디스크 같은 OS 자원을 확인하는 방법은 터미널·서버 코스에서 다룹니다. 이 파트가 다루는 것은 애플리케이션이 스스로 정한 한계입니다. 커넥션 풀 크기, 스레드 풀 크기, 열 수 있는 파일 개수 같은 것들입니다.

이 자원들은 공통된 성질이 있습니다. 한계에 도달하기 전까지는 완전히 멀쩡하다가, 넘는 순간 급격히 무너집니다. 서버 지표를 봐도 CPU와 메모리에 여유가 있어서 원인을 못 찾는 상황이 여기서 나옵니다.

OS 자원
터미널 코스

CPU, 메모리, 디스크 사용량. 서서히 나빠지고 서버 지표에 그대로 보입니다.

애플리케이션 자원
이 파트

풀 크기, 스레드 수, 파일 핸들. 서버 지표에 안 보이고 한계에서 갑자기 무너집니다.

공통 증상
판별

서버는 한가한데 응답이 없거나, 특정 시점부터 오류가 폭증합니다. 부하가 임계치를 넘은 시점을 찾는 것이 핵심입니다.

02

커넥션 풀

가장 자주 마르는 자원입니다. DB 코스 Part 16에서 DB 세션 쪽 증상과 원인 경로를 다뤘고, 여기서는 애플리케이션 쪽에서 어떻게 보이는지를 봅니다.

  • 증상은 커넥션 획득 대기 시간 초과 예외입니다. 메시지에 대기한 시간과 풀 상태가 함께 나오는 경우가 많으니 그대로 읽습니다.
  • 스레드 덤프를 뜨면 다수 스레드가 커넥션 획득 지점에 몰려 있습니다. Part 6의 첫 번째 패턴입니다.
  • 풀 크기와 현재 사용 중인 개수를 지표로 노출해 두면 즉시 판단됩니다. 없으면 스레드 덤프로 추정해야 합니다.
  • 원인은 대개 커넥션을 오래 잡고 있는 코드입니다. 풀을 키우기 전에 DB 코스 Part 16의 확인 순서를 따릅니다.
  • 배치와 온라인이 같은 풀을 공유하면 배치가 도는 동안 온라인이 마릅니다. 성격이 다른 작업은 풀을 나눕니다.
03

스레드 풀

요청을 처리할 스레드가 부족하면 요청이 큐에서 대기하고, 큐도 차면 거부됩니다. 사용자에게는 응답 없음이나 연결 거부로 보입니다.

다만 Part 6에서 짚은 대로, 스레드 풀이 마르는 것은 대개 결과이지 원인이 아닙니다. 스레드가 무언가를 기다리다 안 돌아오기 때문에 부족해지는 것입니다.

최대 스레드 수
설정값

웹 컨테이너의 최대 처리 스레드입니다. 이 값과 현재 사용량을 비교해야 포화 여부가 판단됩니다.

대기 큐
설정값

스레드가 모자랄 때 대기시킬 요청 수입니다. 큐가 길면 응답이 느려지고, 짧으면 빨리 거부됩니다.

비동기 실행기
간과하기 쉬움

직접 만든 스레드 풀도 마릅니다. 요청 처리 스레드만 보다가 놓치는 경우가 있습니다.

키우기 전에
판단

스레드를 늘리면 동시에 DB 커넥션 요구도 늘어납니다. 한쪽만 키우면 병목이 옮겨갈 뿐입니다.

스레드 상태 확인bash
# JVM 전체 스레드 개수
jcmd <PID> Thread.print | grep -c "^\""

# 요청 처리 스레드 중 실제로 일하는 것과 노는 것
jcmd <PID> Thread.print | grep "http-nio" | wc -l
jcmd <PID> Thread.print | grep -A 1 "http-nio" | grep -c "TIMED_WAITING"

# OS 레벨 스레드 수 (한계와 비교)
ls /proc/<PID>/task | wc -l
cat /proc/<PID>/limits | grep processes

요청 처리 스레드가 전부 사용 중인데 TIMED_WAITING이 거의 없다면 풀이 포화된 상태입니다. 이때 무엇을 기다리는지는 Part 6의 방법으로 확인합니다.

04

파일 디스크립터

리눅스에서는 소켓도 파일로 취급됩니다. 그래서 외부 연결이 많은 애플리케이션은 파일을 거의 안 열어도 디스크립터가 고갈될 수 있습니다.

증상이 특이합니다. 파일을 열지도 않았는데 파일 관련 오류가 나거나, 새 연결을 맺지 못하는 형태로 나타납니다.

  • 한계값은 프로세스를 띄운 시점의 설정을 따릅니다. 나중에 시스템 설정을 바꿔도 이미 떠 있는 프로세스에는 적용되지 않습니다.
  • 기본값이 1024인 환경이 아직 있습니다. 연결이 많은 서비스라면 금방 도달합니다.
  • 원인은 대개 닫지 않은 리소스입니다. 한계값을 올리는 것은 시간을 버는 것일 뿐입니다.
  • Part 7의 메모리 누수와 원인이 같은 경우가 많습니다. 리소스를 안 닫으면 양쪽에 다 쌓입니다.
디스크립터 사용량과 한계 확인bash
# 프로세스의 현재 한계값
cat /proc/<PID>/limits | grep "open files"

# 현재 사용 중인 개수
ls /proc/<PID>/fd | wc -l

# 무엇을 열고 있는지 종류별로
ls -l /proc/<PID>/fd | awk '{print $NF}' | sed 's/[0-9]*$//' | sort | uniq -c | sort -rn | head

# 소켓 상태별 개수 (CLOSE_WAIT 가 쌓이면 닫지 않는 코드가 있습니다)
ss -tan | awk '{print $1}' | sort | uniq -c | sort -rn

CLOSE_WAIT 상태가 계속 쌓이면 상대는 연결을 끊었는데 우리 쪽에서 닫지 않고 있다는 뜻입니다. 리소스를 닫지 않는 코드가 있다는 확실한 신호이고, 원인 지점을 좁히는 데 유용합니다.

05

디스크는 2차 장애를 만듭니다

디스크 자체는 OS 자원이지만, 장애 상황에서 특별한 방식으로 문제가 됩니다. 오류가 폭증하면 로그도 폭증하고, 그게 디스크를 채워 새로운 장애를 만듭니다.

그리고 디스크가 차면 로그를 못 남기게 되어 원인 추적도 막힙니다. 가장 나쁜 조합입니다.

악순환
구조

장애 발생 → 오류 로그 폭증 → 디스크 가득 → 로그 기록 실패 → 추가 장애. 진행이 빠릅니다.

로그 로테이션
예방

파일 크기와 보관 개수 제한을 반드시 설정합니다. 총량 상한을 두는 것이 핵심입니다.

덤프 파일
주의

힙 덤프 자동 저장을 켜 뒀는데 OOM이 반복되면 덤프가 쌓여 디스크를 채웁니다. 경로와 여유 공간을 확인합니다.

확인 시점
루틴

Part 2의 증거 확보 스크립트에 디스크 확인이 들어 있는 이유입니다. 초기에 한 번 보면 이 경로를 배제할 수 있습니다.

06

한계값을 평소에 알아 둡니다

자원 고갈 진단이 어려운 이유는 지금 값이 한계인지 아닌지를 모르기 때문입니다. 커넥션 30개가 쓰이고 있다는 사실만으로는 아무것도 판단할 수 없습니다. 한계가 200이면 여유롭고 30이면 포화입니다.

그래서 각 자원의 설정값과 평소 최대 사용량을 미리 정리해 두는 것이 이 파트의 실질적인 결론입니다.

자원 한계값 정리표text
[서비스 자원 한계값 · 2026-07 기준]

자원              설정값    평소 최대   비고
--------------------------------------------------------
DB 커넥션 풀       50       28         인스턴스당. 3대 = DB 세션 150
요청 처리 스레드    200      95         대기 큐 100
비동기 실행기       10       10        상시 포화 → 검토 필요
파일 디스크립터     65536    4200      소켓 포함
힙 메모리          4GB      2.6GB      GC 후 기준
디스크(로그)       50GB     12GB       로테이션 5개 × 20MB

[DB 측 상한]
  sessions = 500  →  애플리케이션 3대 × 50 = 150 (여유 있음)

이 표를 운영 문서에 두고 분기마다 갱신합니다. 장애 상황에서 현재 값과 대조하면 그 자리에서 판단이 끝납니다. 비동기 실행기처럼 평소에 이미 포화인 항목을 발견하는 부수 효과도 있습니다.

트랙 B 마무리

여기까지가 원인을 찾는 기술입니다. 로그를 시간축으로 합쳐 순서를 세우고, 멈춤은 스레드 덤프로, 메모리는 GC 로그와 힙으로, 자원은 한계값 대조로 확인합니다. 공통점이 하나 있습니다. 대부분 평소에 준비해 둬야 장애 때 쓸 수 있다는 것입니다. 요청 식별자, GC 로그, 지표 노출, 한계값 정리표. 트랙 C에서 이 준비를 어떻게 체계로 만드는지 다룹니다.

체크

이 파트 완료 기준