CPU 100% 서버 장애를 겪고 만든 자동 대응 스크립트
그날 밤 무슨 일이 있었냐면
새벽 3시. 자고 있는데 폰이 울렸다. Slack 알림이 아니라 고객사 전화였다.
"서비스 안 되는데요?"
노트북 열고 접속했더니 대충 기억이 안나는데 이런 상태였다.
python3 worker.py 가 CPU를 99.4% 먹고 있었다. 배치 작업이 무한루프에 빠진 거였다.
새벽 3시 반쯤 겨우 정리하고 나서 생각했다. "다음엔 자동으로 감지해서 알려줘야겠다."
근데 거기서 실수를 하나 했다.
프로세스 자동으로 죽였다가 서비스 날린 썰
처음 만든 스크립트에 이런 로직을 넣었다.
# ❌ 이렇게 하면 안 됩니다
if cpu_percent >= 95:
for proc in top_cpu_processes:
if proc.cpu_percent > 80:
proc.kill() # 🔥 이게 문제였다
논리적으로는 맞다. CPU 95% 넘으면 주범 프로세스 죽이면 되잖아. 근데 현실은 달랐다.
💀
gunicorn worker가 같이 죽었다
CPU 높은 프로세스 죽였더니 마침 그 옆에서 실제 API 요청 처리하던 worker도 같이 날아갔다. 장애 해결하려다 장애 심화.
😱
스크립트가 판단을 못 한다
배치 작업인지 API 서버인지 DB인지 스크립트는 모른다. CPU 높다고 무조건 죽이면 진짜 중요한 프로세스도 같이 간다.
⚠️
kill은 사람이 해야 한다
상황 판단은 결국 사람 몫이다. 스크립트는 빠르게 알려주고, 안전한 것만 자동으로 처리하면 충분하다.
그래서 다시 만든 v2 — 철학을 바꿨다
자동 킬을 전부 제거하고 역할을 명확히 나눴다.
# v2 철학
스크립트가 할 일 → 감지 + 안전한 조치 + 빠른 알림
사람이 할 일 → 판단 + kill + 근본 원인 해결
스크립트가 자동으로 하는 것 (안전한 것만)
✅ 페이지 캐시 정리
서비스 영향 없이 메모리 일부 회수.
drop_caches 사용.✅ 스왑 재활성화
단편화된 스왑 정리.
swapoff -a && swapon -a⚙️ 서비스 재시작 (선택)
설정 파일에서 명시한 서비스만. 기본값 비활성화.
❌ 프로세스 자동 kill
제거. 판단은 사람이 한다.
Slack 알림에 뭐가 오냐면
새벽에 알림 받았을 때 멍한 상태로 바로 조치할 수 있게 복붙용 명령어까지 알림에 넣었다.
🚨 [CRITICAL] 서버 이상 감지 — production-server-01
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CPU 99.4% 🔴 Memory 88.2% ⚠️
Load 24.31 / 22.18 / 19.44
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🔥 CPU 주범 TOP 3
`python3` (PID 18842) — 99.4%
`gunicorn` (PID 18901) — 0.3%
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 즉시 조치 가이드 (복붙용) 예시
top -p 18842
ps aux | grep python3
kill -15 18842 # graceful
kill -9 18842 # 최후 수단
설치 & 사용법
# 1. 설치
pip install psutil requests
# 2. CONFIG 수정
vim auto_response.py
# SLACK_WEBHOOK, SERVER_NAME 입력
# 3. 현재 상태 확인
python3 auto_response.py --status
# 4. Slack 테스트
python3 auto_response.py --test-slack
# 5. crontab 등록 (5분마다)
crontab -e
*/5 * * * * python3 /opt/scripts/auto_response.py
배운 것
자동화는 만능이 아니다. 판단이 필요한 영역은 사람에게 남겨야 한다. 스크립트는 사람이 더 빠르게, 덜 멍한 상태로 판단할 수 있도록 돕는 도구일 뿐이다.
새벽 3시에 알림 받아서 Slack 열었을 때 주범 PID랑 복붙 명령어가 바로 있으면, 머리가 반쯤 잠든 상태에서도 30초 안에 조치할 수 있다. 그게 이 스크립트의 목표다.