이 글에서 얻는 것
- “요청이 안 된다/느리다” 상황에서 어디부터 확인해야 하는지(프로세스→로그→네트워크→의존성) 순서가 생깁니다.
- 운영에서 자주 쓰는 최소 명령어(
ps/top/journalctl/ss/lsof/curl/dig/df)로 문제 범위를 빠르게 좁힐 수 있습니다. - “애플리케이션 문제”로 보이던 이슈가 사실은 DNS/포트/리소스/디스크일 수 있음을 감각적으로 이해합니다.
0) 백엔드 장애는 보통 이렇게 시작한다
대표 증상:
timeout(연결은 되는데 응답이 없다)connection refused(포트가 안 열렸거나 프로세스가 없다)- 5xx(특히 502/504) 증가(업스트림/프록시/LB/타임아웃 계층 가능)
- CPU/메모리 급등, OOMKilled, 디스크 꽉 참
이 글은 “원인을 바로 맞추는” 게 아니라, 원인 후보를 빠르게 줄이는 루틴을 만드는 게 목표입니다.
1) 프로세스/자원: “서버가 살아있는가?”
1-1) CPU/메모리/로드 확인
top/htop(있다면): CPU, 메모리, load averagetop -H: 스레드 단위로 확인(스레드 폭주/락 경합 짐작)free -h: 메모리 여유(캐시 포함 해석 필요)vmstat 1: run queue, swap, IO wait 같은 흐름 확인
실무 감각:
- CPU 100%가 “연산”인지 “스핀락/바쁜 대기”인지 구분이 필요합니다(스레드 덤프와 연결).
- 메모리가 부족해 swap이 치면, 레이턴시가 갑자기 나빠질 수 있습니다.
1-2) 프로세스가 떠 있는지 / 어디를 리슨하는지
ps aux | rg <process>: 프로세스 존재 확인ps -o pid,ppid,cmd,%cpu,%mem -p <pid>: 특정 PID 상태 확인
컨테이너라면 “호스트가 아니라 컨테이너 내부”에서 확인해야 하는 경우가 많습니다.
2) 로그: “무슨 에러가 나는가?”
2-1) systemd(journalctl) 기반일 때
journalctl -u <service> -n 200 --no-pager: 최근 200줄journalctl -u <service> -f: 실시간 followjournalctl -u <service> --since \"10 minutes ago\": 시간 범위
2-2) 파일 로그일 때
tail -n 200 -f /var/log/...rg \"ERROR|Exception\" -n <logfile>
실무 팁:
- “스택트레이스가 없고 타임아웃만 있다”면, 애플리케이션이 아니라 네트워크/의존성/풀 고갈일 가능성도 큽니다.
- 반드시 traceId/correlationId를 같이 보는 습관을 들이면 디버깅 속도가 크게 빨라집니다.
3) 포트/연결: “요청이 어디까지 도달하나?”
3-1) 포트 리슨 확인
ss -lntp: TCP 리슨 소켓 확인(프로세스까지)lsof -iTCP -sTCP:LISTEN -nP | rg <port>: 특정 포트 리슨 확인
connection refused는 보통:
- 포트가 열려 있지 않거나
- 방화벽/보안그룹/NACL이 차단하거나
- 잘못된 IP/포트로 붙고 있을 때
중 하나입니다.
3-2) 연결이 쌓이는지 확인
ss -antp | head: ESTABLISHED, SYN-SENT, TIME-WAIT 등 상태를 봅니다.
실무 감각:
TIME-WAIT이 과도하면 짧은 커넥션을 너무 많이 만들고 있을 수 있습니다(keep-alive, 커넥션 풀).SYN-SENT가 많으면 대상이 응답하지 않거나 네트워크가 막혔을 가능성이 큽니다.
4) DNS/HTTP: “이 도메인이 어디로 가는가?”
4-1) DNS 확인
dig <domain> A +shortdig <domain> AAAA +short(IPv6 이슈 확인)dig +trace <domain>(권한/전파/라우팅 문제 추적)
4-2) 실제 호출을 재현(curl)
curl -v https://api.example.com/healthcurl -I https://api.example.com/(헤더만)curl --resolve api.example.com:443:1.2.3.4 https://api.example.com/health(DNS를 우회해 특정 IP로 강제)
포인트:
- “서버는 정상인데 브라우저/클라이언트만 실패”면 DNS/프록시/인증 헤더 같은 계층일 수 있습니다.
5) 디스크/파일: “로그가 쌓여서 죽는” 사고를 막기
df -h: 디스크 사용량df -i: inode 고갈(파일이 너무 많아도 터짐)du -sh * | sort -h: 무엇이 공간을 먹는지
실무에서 자주 터지는 패턴:
- 로그/덤프 파일이 무한히 쌓여 디스크 100% → 애플리케이션이 쓰기 실패 → 장애
6) 10분 디버깅 루틴(추천)
- 증상 분류:
refusedvstimeoutvs 5xx - 프로세스/리소스:
top,ps로 “살아있는가/포화인가” - 로그:
journalctl/파일 로그에서 에러/스택트레이스 확인 - 포트/연결:
ss -lntp(리슨) →ss -antp(연결 상태) - DNS/HTTP 재현:
dig,curl -v로 “어디까지 가는지” 확인 - 의존성(DB/외부 API): 타임아웃/커넥션 풀/레이트리밋 확인(애플리케이션 지표와 연결)
연습(추천)
- 간단한 서버를 띄운 뒤(로컬/컨테이너), 포트를 바꿔
connection refused를 만들고ss/lsof/curl로 원인을 찾아보기 - DNS를 잘못된 레코드로 가정하고
dig와curl --resolve로 문제를 분리해보기 - 디스크를 일부러 채우는 테스트 환경에서 로그가 쌓일 때 어떤 장애가 나는지(쓰기 실패/에러 로그) 재현해보기
💬 댓글