장애 원인을 찾을 때 가장 위험한 접근법 7가지
서버 장애가 발생했을 때 가장 어려운 것은 장애 자체를 복구하는 일이 아니다. 실제 운영 환경에서는 수많은 증상 중에서 진짜 원인을 찾아내는 과정이 훨씬 어렵다.
CPU 사용률이 갑자기 올라갈 수도 있고, Load Average가 증가할 수도 있으며, 웹 요청이 느려지거나 DB Connection이 부족해질 수도 있다. 문제는 이런 현상 대부분이 원인이 아니라 다른 문제에서 파생된 결과일 수 있다는 점이다.
예를 들어 웹서버 응답이 느리다고 해서 반드시 Nginx가 문제인 것은 아니다. 뒤쪽의 애플리케이션 서버가 느릴 수도 있고 데이터베이스 Query가 지연되고 있을 수도 있으며 네트워크 Packet Loss가 발생했을 수도 있다.
그래서 장애 분석에서 가장 위험한 행동은 명령어를 모르는 것이 아니라 근거 없이 원인을 결정하는 것이다.
이번 글에서는 실제 Linux 서버 장애를 분석할 때 운영자가 특히 피해야 할 접근법 7가지를 살펴본다.
장애 분석을 어렵게 만드는 가장 큰 원인
서버 장애는 대부분 하나의 지표만으로 설명되지 않는다.
일반적인 웹 서비스 구조만 보더라도 다음과 같은 계층을 거쳐 요청이 처리된다.
Client
→ Network
→ Load Balancer
→ Nginx
→ Application
→ Database
→ Storage
이 가운데 어느 한 부분에서 병목이 발생하면 사용자에게는 단순히
사이트가 느리다
라는 하나의 증상으로 보일 수 있다.
따라서 장애 분석의 핵심은 처음부터 원인을 맞히는 것이 아니다.
증상을 수집하고 가능성을 하나씩 제거하면서 원인의 범위를 좁혀가는 과정이 중요하다.
하지만 실제 장애 상황에서는 서비스 복구에 대한 압박 때문에 이런 기본 원칙을 무시하기 쉽다.
CPU 사용률이 높다는 이유만으로 CPU를 원인으로 판단하기
장애가 발생하면 가장 먼저 확인하는 지표 가운데 하나가 CPU 사용률이다.
top 또는 mpstat -P ALL 1 같은 명령으로 CPU 상태를 확인할 수 있다.
문제는 CPU 사용률이 100%라는 사실만 보고 바로 CPU 부족을 장애 원인으로 결정하는 것이다.
CPU 사용률 상승은 원인일 수도 있지만 다른 문제의 결과일 수도 있다.
예를 들어 애플리케이션에서 무한 Loop가 발생하면 CPU 사용률이 올라갈 수 있다.
반대로 요청량이 갑자기 증가하면서 정상적인 처리량 증가 때문에 CPU가 높아질 수도 있다.
두 상황은 CPU 사용률만 보면 비슷하지만 해결 방법은 완전히 다르다.
특히 top을 확인할 때 전체 CPU 사용률만 보는 것이 아니라
- 어떤 Process가 CPU를 사용하는지
- user CPU와 system CPU 비율은 어떤지
- iowait가 증가했는지
- 특정 CPU Core에 부하가 집중됐는지
까지 함께 봐야 한다.
CPU가 높다는 것은 현상이다.
장애 분석에서는 반드시
왜 CPU가 높아졌는가
까지 내려가야 한다.
Load Average가 높으면 서버가 과부하라고 판단하기
Linux 장애 분석에서 가장 자주 오해되는 지표 중 하나가 Load Average다.
uptime
명령을 실행하면 다음과 같은 값을 볼 수 있다.
load average: 8.25, 7.91, 6.30
많은 운영자가 이 숫자가 높으면 CPU가 부족하다고 생각한다.
하지만 Linux의 Load Average에는 CPU 사용을 기다리는 Task뿐 아니라 특정 조건에서 I/O 작업을 기다리는 Task도 포함될 수 있다.
따라서 Load Average가 20이라고 해서 CPU가 100%라는 의미는 아니다.
예를 들어 Storage 응답이 느려져 많은 Process가 I/O를 기다리고 있다면 CPU 사용률이 낮은데도 Load Average가 크게 증가할 수 있다.
이럴 때는
vmstat 1 을 통해 runnable Process와 I/O Wait 상태를 확인하고,
iostat -x 1 을 이용해 Disk latency와 utilization을 함께 확인하는 것이 좋다.
즉, Load Average가 높다 → CPU 부족
이라는 단순한 공식으로 접근하면 엉뚱하게 CPU 증설을 하고도 장애가 해결되지 않을 수 있다.
로그에서 ERROR 하나를 발견하고 원인으로 확정하기
서버 장애가 발생하면 로그를 확인하는 것은 매우 중요하다.
하지만 로그에서 눈에 띄는 ERROR 한 줄을 발견했다고 해서 바로 장애 원인으로 판단하는 것은 위험하다.
예를 들어 Nginx error log에 다음과 같은 메시지가 있다고 가정해보자.
upstream timed out
이 메시지는 Nginx가 일정 시간 동안 upstream 서버의 응답을 받지 못했다는 의미다.
하지만 이것만으로 Nginx에 문제가 있다고 판단할 수는 없다.
실제 원인은
Application 처리 지연
Database Query 지연
Connection Pool 고갈
외부 API 응답 지연
Backend 서버 과부하
등일 수 있다.
로그는 대부분 관찰된 현상을 기록할 뿐 전체 원인을 설명해주지는 않는다.
따라서 오류 메시지를 발견하면 반드시 장애가 발생한 시간과 비교해야 한다.
grep "Sep 22 14:" /var/log/nginx/error.log
처럼 장애 시간대를 기준으로 로그를 좁혀보고 다른 서버와 애플리케이션 로그의 Timestamp도 함께 비교해야 한다.
장애 분석에서 로그 한 줄보다 중요한 것은 시간의 흐름이다.
장애가 발생하자마자 서비스를 재시작하기
운영 환경에서 가장 유혹적인 방법 중 하나다.
서비스가 이상하면 일단
systemctl restart nginx 또는 systemctl restart myapp 를 실행하는 것이다.
재시작으로 장애가 해결되는 경우도 있다.
하지만 원인을 확인하기 전에 재시작하면 가장 중요한 장애 증거를 잃을 수 있다.
Process의 Memory 상태, Connection 상태, Thread 상태, 열려 있던 File Descriptor, Socket 상태, Process별 CPU 사용률 등 일부 정보는 Process가 종료되는 순간 사라진다.
Memory Leak 때문에 장애가 발생했다면 재시작 후 Memory 사용량이 정상으로 돌아오면서 문제 자체가 사라진 것처럼 보일 수도 있다.
하지만 시간이 지나면 같은 장애가 다시 발생한다.
가능하다면 재시작 전에 최소한 다음 정보는 확보하는 것이 좋다.
top -b -n 1
free -m
vmstat 1 5
ss -s
df -h
그리고 문제가 되는 Process가 있다면
ps -ef 또는 ps aux 를 이용해 Process 상태도 남겨두는 것이 좋다.
서비스 복구가 가장 중요한 긴급 상황이라면 재시작이 필요할 수 있다.
다만 복구와 원인 분석은 별개의 과정이라는 점을 기억해야 한다.
최근 변경 사항을 확인하지 않고 서버부터 분석하기
어제까지 정상적으로 동작하던 서버가 갑자기 장애를 일으켰다면 가장 먼저 확인해야 하는 질문이 있다.
최근에 무엇이 바뀌었는가?
애플리케이션 배포, Nginx 설정 변경, Kernel Parameter 변경, DB Index 변경, Firewall 정책 변경, Traffic 증가, 인프라 구성 변경 등이 대표적이다.
실제 장애에서는 새로운 코드가 배포된 직후 Connection이 증가하거나 Query 실행 계획이 바뀌면서 CPU 부하가 급증하는 경우도 있다.
그런데 이런 변경 이력을 확인하지 않고 서버의 모든 지표부터 조사하기 시작하면 분석 범위가 지나치게 넓어진다.
장애 시점을 T0라고 한다면 다음처럼 Timeline을 만드는 방법이 효과적이다.
13:50 애플리케이션 배포
14:03 응답시간 증가
14:05 DB Connection 증가
14:07 HTTP 502 증가
14:10 장애 감지
이런 Timeline만 만들어도 원인의 범위가 크게 줄어든다.
장애 분석에서 시간 상관관계는 매우 강력한 단서다.
물론 배포 직후 장애가 발생했다고 해서 반드시 배포가 원인이라는 뜻은 아니다.
변경 사항은 원인을 확정하는 증거가 아니라 우선적으로 검증해야 할 가설이다.
여러 설정을 한꺼번에 변경하기
장애 상황에서 Timeout도 늘리고 Worker 수도 늘리고 Kernel Parameter도 변경하고 서버까지 재시작하는 경우가 있다.
운이 좋으면 장애는 해결될 수 있다.
하지만 이후 더 큰 문제가 발생한다.
무엇 때문에 해결됐는지 알 수 없게 된다.
예를 들어 다음 설정을 동시에 변경했다고 가정해보자.
worker_connections 증가
proxy_read_timeout 증가
somaxconn 증가
Application 재시작
서비스가 정상화됐다고 해도 어떤 변경이 효과가 있었는지 확인하기 어렵다.
더 나쁜 경우 하나의 설정은 문제를 해결했지만 다른 설정이 새로운 잠재적 장애를 만들었을 수도 있다.
따라서 가능하면
가설 설정
→ 하나의 변경
→ 결과 관찰
→ 다음 판단
순서로 접근해야 한다.
장애 분석은 단순한 복구 작업이 아니라 하나의 실험과 비슷하다.
변수를 동시에 여러 개 변경하면 실험 결과를 해석할 수 없게 된다.
한 서버만 보고 전체 서비스의 문제를 판단하기
분산된 서버 환경에서는 특히 위험한 접근이다.
Web Server가 10대 있고 그중 한 대에서 CPU가 100%라고 가정해보자.
해당 서버만 보면 심각한 장애처럼 보인다.
하지만 전체 서버를 비교해보면 나머지 9대는 CPU가 20%일 수도 있다.
이 경우 문제는 전체 트래픽 증가가 아니라 Load Balancer의 Traffic 분산 문제일 가능성이 있다.
반대로 모든 Web Server의 CPU가 동시에 증가했다면 전체 Request 증가나 Backend 병목을 의심할 수 있다.
따라서 장애 분석에서는 항상
이 현상이 한 서버에서만 발생하는가?
라는 질문이 필요하다.
예를 들어 여러 서버를 비교해
CPU
Memory
Connection
Request Per Second
Response Time
Error Rate
등을 확인하면 장애 범위를 빠르게 좁힐 수 있다.
한 서버의 절대값보다 정상 서버와 장애 서버의 차이가 더 중요한 단서가 되는 경우가 많다.
장애 분석은 원인을 맞히는 게임이 아니다
숙련된 운영자라고 해서 장애 화면을 보자마자 원인을 정확하게 맞히는 것은 아니다.
오히려 경험이 많은 운영자일수록 처음부터 하나의 원인에 집착하지 않는다.
예를 들어 응답 속도가 느려졌다면 다음과 같이 가설을 나눌 수 있다.
Network 지연인가?
↓
Web Server 병목인가?
↓
Application 처리 지연인가?
↓
Database 문제인가?
↓
Storage I/O 문제인가?
↓
외부 API 문제인가?
그리고 각 계층의 지표를 확인하면서 가능성을 제거한다.
이를 장애 범위를 좁혀가는 방식이라고 볼 수 있다.
특히 중요한 것은 정상 상태의 기준값을 알고 있는 것이다.
평소 CPU가 30%였던 서버가 80%가 된 것과 평소 75%였던 서버가 80%가 된 것은 의미가 다르다.
그래서 운영 환경에서는 장애가 없을 때부터 CPU, Memory, Disk I/O, Network Traffic, Connection, Response Time 같은 주요 지표를 지속적으로 수집해야 한다.
실제 장애에서는 어떤 순서로 분석해야 할까?
장애가 발생하면 처음부터 특정 Component를 원인으로 결정하지 않는 것이 중요하다.
먼저 장애 범위를 확인한다.
전체 서비스 문제인지, 특정 서버 문제인지, 특정 API 문제인지 구분한다.
그다음 장애 발생 시간을 정확하게 잡는다.
이후 변경 이력과 트래픽 변화를 확인하고 CPU, Memory, Disk, Network, Connection 같은 시스템 지표를 확인한다.
그다음 Web Server, Application, Database 순서로 범위를 좁힌다.
예를 들면 다음 흐름이다.
사용자 장애 발생
↓
장애 범위 확인
↓
장애 발생 시간 확인
↓
최근 변경 사항 확인
↓
CPU / Memory / Disk / Network 확인
↓
Connection 상태 확인
↓
Application 상태 확인
↓
Database 상태 확인
↓
로그 Timestamp 비교
↓
가설 검증
↓
원인 확정
이렇게 접근하면 장애 상황에서도 분석 방향을 잃을 가능성이 줄어든다.
정리
서버 장애 분석에서 가장 위험한 것은 Linux 명령어를 많이 모르는 것이 아니다.
더 위험한 것은 충분한 근거 없이 원인을 결정하는 습관이다.
CPU가 높다고 CPU를 원인으로 판단하고, Load Average가 높다고 서버 성능 부족으로 결론 내리고, ERROR 로그 하나를 발견했다고 해당 메시지를 장애 원인으로 확정하면 실제 문제와 전혀 다른 방향으로 갈 수 있다.
특히 장애가 발생하자마자 서비스를 재시작하거나 여러 설정을 동시에 변경하면 중요한 증거까지 사라진다.
좋은 장애 분석은 복잡하지 않다.
증상 확인 → 장애 범위 확인 → 시간대 확인 → 변경 사항 확인 → 지표 분석 → 가설 설정 → 검증
이 순서를 반복하는 것이 핵심이다.
결국 서버 운영에서 중요한 능력은 장애 원인을 단번에 맞히는 능력이 아니다.
수많은 가능성 가운데 근거 없는 가정을 하나씩 제거하면서 실제 원인까지 논리적으로 범위를 좁혀가는 능력이 진짜 장애 대응 능력이다.




댓글 0
첫 댓글을 남겨보세요.