최종 업데이트: 2026년 6월. 원문의 단계별 로그 분석 절차는 그대로 유효하며, OpenTelemetry 표준화·eBPF 관측성·AI 보조 로그 분석·공급망/구성 드리프트 등 현재 시점의 트러블슈팅 기법을 보강했습니다. (아래 “빠른 대응 체크리스트”부터 보셔도 됩니다.)
개요: 왜 500 Internal Server Error는 늘 어렵게 느껴질까?
500 Internal Server Error는 서버 내부에서 예기치 않은 예외가 발생했음을 의미합니다. 클라이언트 요청이 잘못된 것도 아니고, 네트워크가 완전히 끊어진 것도 아닌데 서버가 “처리할 수 없다”고 말하는 상황이죠. 특히 2024년 현재에는 컨테이너, 쿠버네티스, 서비스 메쉬, HTTP/2·HTTP/3, CDN·WAF·API Gateway까지 아키텍처가 복잡해지면서, 500 오류의 근본 원인을 추적하는 일이 더 복잡해졌습니다.
이 글은 시스템 관리자를 위한 실전형 가이드입니다. 단발성 처방이 아니라, 재현-로그 분석-원인 규명-영구 해결까지 단계별로 따라갈 수 있도록 설계했습니다. 실제 명령어, 설정 예시, 체크리스트, 예방 전략까지 모두 포함하여 “다음 장애 때 바로 쓸 수 있는” 형태로 제공합니다.
빠른 대응 체크리스트 (TL;DR)
긴 글을 읽기 전에, 운영 중이라면 아래부터 실행하세요.
- 영향 범위 파악: 특정 엔드포인트/테넌트/리전/릴리스 버전만 영향을 받는가?
- 롤백 가능 여부: 직전 배포로 되돌릴 수 있는가? Blue-Green/Canary면 즉시 전환.
- 임시 완화책:
- CDN/캐시를 활성화해 읽기 요청 부하를 줄임
- 특정 경로(파일 업로드 등) 스로틀링
- 오류 페이지 커스터마이즈로 사용자 경험 악화 최소화
- 모니터링 알람 확인: 5xx 비율, p95 지연, OOM, CPU Throttle, DB 연결 수
- 공용 공지/상태 페이지 업데이트: 사용자·내부 이해관계자 커뮤니케이션
이후에 아래 단계별 가이드를 통해 근본 원인을 찾아 대응합니다.
500 에러 이해하기: 5xx 스펙트럼 속에서의 500
- 500: 서버 내부 예외(가장 범용적, 애플리케이션 예외·핸들링 누락)
- 502 Bad Gateway: 프록시/로드밸런서가 업스트림과 통신 실패
- 503 Service Unavailable: 과부하/점검/리소스 부족(일시적)
- 504 Gateway Timeout: 업스트림 처리 시간 초과
- 521/522/523 등: 특정 CDN/프록시 벤더 전용 코드
팁: 500과 502/504를 구분하는 것만으로도 원인 영역(애플리케이션 vs 프록시/네트워크)을 빠르게 좁힐 수 있습니다.
아키텍처 지형 파악: 500은 어디에서 발생하는가?
현대 스택에서 한 요청은 다음을 거칩니다:
Client → CDN/WAF → LB/Ingress → Reverse Proxy(Nginx/Apache/Envoy) → App Server(Gunicorn/uWSGI/PHP-FPM/Node) → DB/Cache/Queue + 외부 API
500이 실제로 발생하는 지점은 다양합니다. 첫 단계는 “어디에서 500이 내려오는가”를 식별하는 것입니다.
- CDN/WAF에서 내려온 5xx? 벤더 로그/대시보드 확인
- Ingress/LB 레벨? Target group 헬스, 백엔드 5xx 비율 확인
- Reverse Proxy(Nginx/Apache) 레벨? error_log의 upstream 메시지 분석
- App 레벨? 스택트레이스, 프레임워크 예외 처리
- DB/외부 API? 연결/타임아웃/쿼리 성능 문제
단계별 로그 분석 가이드
1) 상관관계 ID로 요청 추적 세팅
- Nginx:
$request_id, 또는 헤더X-Request-ID전파 - 애플리케이션 로거: 모든 로그에 request_id 포함
- 분산 트레이싱: OpenTelemetry(Trace/Span ID), W3C Trace Context 헤더(
traceparent) 사용
Nginx 예시:
map $http_x_request_id $req_id {
default $http_x_request_id;
"" $request_id;
}
log_format main 'time:$time_iso8601 req_id:$req_id '
'client:$remote_addr "$request" status:$status '
'upstream:$upstream_addr rt:$request_time urt:$upstream_response_time';
access_log /var/log/nginx/access.log main;
proxy_set_header X-Request-ID $req_id;
이렇게 해두면 하나의 요청을 LB → Nginx → App → DB까지 일관되게 추적할 수 있습니다.
2) 접근 로그로 증상 범위 좁히기
- 특정 경로/메서드/클라이언트에서만 500이 나는가?
- 500의 비율이 급증한 시점은 언제인가? 직전 배포/설정 변경과 일치하는가?
Nginx grep 예시:
# 최근 10분간 500 발생 상위 경로 집계
awk -v d="$(date -u +"%d/%b/%Y:%H:%M")" '$4 ~ d && $9 ~ /500/ {print $7}' /var/log/nginx/access.log \
| sort | uniq -c | sort -nr | head
3) 에러 로그로 원인 유형 확인
- Nginx error_log에서 자주 보이는 패턴:
- upstream prematurely closed connection
- connect() failed (111: Connection refused)
- upstream timed out (110: Connection timed out)
예시:
2024/06/05 11:02:31 [error] 12345#0: *989 upstream prematurely closed connection while reading response header from upstream,
client: 203.0.113.9, server: example.com, request: "POST /api/upload HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000"
→ PHP-FPM/애플리케이션에서 프로세스 크래시/응답 헤더 생성 전에 종료된 상황을 암시.
4) 애플리케이션 로그/스택트레이스
- Python/Gunicorn:
[2024-06-05 11:02:31 +0000] [17] [ERROR] Error handling request /api/orders
Traceback (most recent call last):
...
psycopg2.OperationalError: FATAL: too many connections
- Node/Express:
TypeError: Cannot read properties of undefined (reading 'id')
at /app/routes/order.js:42:18
- PHP:
PHP Fatal error: Uncaught PDOException: SQLSTATE[HY000] [1040] Too many connections in /var/www/html/db.php:12
이 단계에서 원인 후보군이 크게 줄어듭니다.
5) 시스템/컨테이너/Kubernetes 이벤트
- systemd:
journalctl -u php-fpm --since "10 min ago" | tail -n 100
- Docker:
docker logs --tail 200 <container_id>
docker inspect <container_id> --format '{{.State.OOMKilled}}'
- Kubernetes:
kubectl get pods -n prod
kubectl describe pod <pod> -n prod | egrep -i "oom|killed|restart|probe"
kubectl logs <pod> -c app --since=10m
kubectl logs <pod> -c app -p # 이전 컨테이너 로그
OOMKilled, CrashLoopBackOff, liveness/readiness 실패가 보이면 리소스/헬스체크 전략을 의심합니다.
6) 외부 구성요소 로그
- DB(PostgreSQL/MySQL) 쿼리 슬로우 로그, 연결 제한, 데드락
- Redis timeout/evicted keys
- 메시지 큐(예: RabbitMQ) connection/channel 에러
- WAF/ModSecurity 감지 로그
ModSecurity 예시:
[client 198.51.100.10] ModSecurity: Access denied with code 500 (phase 2).
Pattern match "(?i:<script)" at ARGS:comment. [id "942100"] [msg "XSS Attack Detected"]
규칙이 차단하면서 500을 반환하는 구성일 수 있습니다(보통은 403이 적절).
문제 재현: 유효한 증거 만들기
- 최소 재현 요청을 만든다.
- 헤더/바디/메서드/크기/프로토콜(HTTP/1.1 vs HTTP/2/3)을 동일하게 맞춘다.
- 동시성/부하가 필요한 경우
hey,ab,wrk등으로 부하 재현.
cURL 예시:
# 상세한 요청/응답, HTTP/2 사용
curl -vk --http2 https://api.example.com/orders \
-H "X-Request-ID: test-123" \
-H "Content-Type: application/json" \
--data '{"userId":123, "items":[{"sku":"A1","qty":2}]}'
특정 클라이언트만 실패한다면:
- User-Agent, 압축(Content-Encoding), 전송 인코딩(Chunked), Keep-Alive, 대용량 업로드 등 변수를 조정해 재현합니다.
원인별 트러블슈팅 시나리오와 해결
1) 애플리케이션 예외/핸들링 누락
증상:
- 스택트레이스가 로그에 남음
- 특정 경로/입력에서만 500 재현
해결:
- 프레임워크의 글로벌 예외 핸들러를 구현하여 표준화된 에러 응답(JSON) 반환
- 입력 검증 강화(스키마 검증, JSON 파서 예외 처리)
- 널/경계값 처리
- 비즈니스 로직에서 예상 가능한 오류는 4xx로 매핑
Node/Express 예시:
app.use((err, req, res, next) => {
const reqId = req.headers['x-request-id'] || '-';
console.error(`req_id=${reqId}`, err);
res.status(500).json({ error: 'Internal Server Error', requestId: reqId });
});
2) 파일 권한/SELinux/AppArmor
증상:
- Permission denied, open() 실패, php-fpm에서 디렉터리 접근 불가
- SELinux enforced 환경에서 평소에는 없던 500
해결:
# 권한/소유자 정정
chown -R www-data:www-data /var/www/html/storage
chmod -R 750 /var/www/html/storage
# SELinux 컨텍스트 확인/수정
ls -Z /var/www/html/storage
semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/storage(/.*)?"
restorecon -Rv /var/www/html/storage
3) 업스트림 타임아웃/버퍼 문제(Nginx ↔ PHP-FPM/Gunicorn/uWSGI)
증상:
- upstream timed out / prematurely closed connection
- 큰 응답/업로드에서만 500
해결(Nginx):
proxy_read_timeout 120s;
proxy_send_timeout 120s;
proxy_buffers 16 512k;
proxy_busy_buffers_size 512k;
proxy_buffer_size 512k;
FastCGI(PHP-FPM):
fastcgi_read_timeout 120s;
fastcgi_buffers 16 512k;
애플리케이션 서버:
- Gunicorn:
--timeout 120 --workers 4 --worker-class gthread - uWSGI:
harakiri = 120 - PHP-FPM:
pm.max_children적정값, 느린 로그(slowlog) 활성화
4) 데이터베이스 연결/성능 문제
증상:
- Too many connections, timeout, deadlock
- 트래픽 피크에서만 500
해결:
- 커넥션 풀 크기 조정(웹 인스턴스 수 × 워커 수보다 과도하게 크지 않게)
- PgBouncer/HikariCP 등 풀러 적용
- 슬로우 쿼리 튜닝(인덱스 추가, N+1 제거, 캐시)
- DB 파라미터 조정:
max_connections,work_mem,innodb_buffer_pool_size등
PostgreSQL 슬로우 로그 활성화 예시:
ALTER SYSTEM SET log_min_duration_statement = '500ms';
SELECT pg_reload_conf();
5) 메모리 부족/OOMKilled
증상:
- Kubernetes 이벤트에 OOMKilled
- 재시작 증가, 500 동반
해결:
- 리소스 요청/제한 재설정:
resources.requests.memory,resources.limits.memory - 메모리 프로파일링(힙 덤프, leak 확인)
- 응답 압축/버퍼 제한, 대용량 결과 스트리밍 처리
- 연결 풀/캐시 크기 제한
6) 업로드/바디 크기 제한
증상:
- 특정 크기 이상 파일 업로드 500/502
해결:
- Nginx:
client_max_body_size 50m; - PHP:
upload_max_filesize,post_max_size - App/Framework: 바디 파서의 limit 옵션
7) 리라이트/프록시 루프 및 헤더 문제
증상:
- 내부 리다이렉트 반복/루프, 헤더 초과, 쿠키 과다
해결:
- 리라이트 규칙 정규식 점검,
break/last사용 여부 확인 - 헤더 크기 제한 상향:
large_client_header_buffers,proxy_buffer_size
8) 보안 모듈/규칙과 충돌
증상:
- ModSecurity/WAF 로그에 룰 트리거, 500 반환
해결:
- 의도치 않은 룰은 화이트리스트 또는 예외 범위 지정
- 차단 시 상태 코드를 403으로 일관되게 설정
- 서명 기반에서 애플리케이션 맥락 기반(Positive Security)로 전환 검토
9) 배포/마이그레이션 불일치
증상:
- 배포 직후 500 급증
- DB 마이그레이션 누락, 환경변수/시크릿 미설정
해결:
- 마이그레이션 선적용 및 롤백 가능하게 구성
- 시크릿/설정 Drift 탐지(CI에서 스키마 검증)
- Blue-Green, Canary와 헬스 체크 기반 트래픽 전환
10) 외부 API/의존성 장애
증상:
- 외부 서비스 타임아웃/오류를 내부 500으로 전파
해결:
- 타임아웃/재시도 설정, Circuit Breaker, 폴백 캐시
- 3rd-party 별 상태 페이지와 지표 연동
- 4xx/5xx 매핑을 비즈니스 로직에 맞게 변환
Kubernetes/컨테이너 환경 특화 트러블슈팅
Ingress/Service/Pod 레벨
- Ingress(NGINX Ingress Controller) 타임아웃:
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
nginx.ingress.kubernetes.io/proxy-send-timeout: "120"
- 헬스체크 실패로 재시작:
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
timeoutSeconds: 2
periodSeconds: 10
failureThreshold: 3
헬스 엔드포인트는 가벼워야 하며, 외부 의존성(DB 등)과 분리된 “자기 생존 여부”를 반환하는 것이 좋습니다.
리소스/오토스케일링
- HPA 기준을 CPU뿐 아니라 RPS/큐 길이/맞춤 지표(예: 5xx 비율)로 보완
- PodDisruptionBudget으로 롤링 업데이트 중 가용성 보장
- Readiness 게이트로 의존성이 준비되지 않으면 트래픽 유입 차단
서비스 메시(Istio/Linkerd/Envoy)
- mTLS 불일치/인증서 만료 → 5xx
- Envoy 접근/에러 로그에서 upstream reset/overflow 확인
- VirtualService에서 타임아웃/재시도/서킷브레이커 정책 설정
Nginx/Apache 설정: 디버깅과 안정성
Nginx 디버그 모드(일시)
error_log /var/log/nginx/error.log debug;
운영에서는 디스크/성능 부담을 고려해 단시간만 활성화하세요.
고가용성/탄력성 옵션
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
proxy_next_upstream_tries 3;
keepalive_timeout 65;
sendfile on;
tcp_nodelay on;
Apache 로그 확장
LogLevel core:info mod_proxy:debug
ErrorLogFormat "[%{u}t] [${log_module}:%l] [pid %P] [req %{UNIQUE_ID}e] [client %a] %M"
관측 가능성: 5xx를 데이터로 다루기
- 대시보드 핵심:
- 5xx 비율(서비스/엔드포인트별)
- p95/99 지연, 에러와 지연의 상관
- 인스턴스 수, 재시작 횟수, OOM, CPU Throttle
- DB 연결 수/대기, 슬로우 쿼리
- 로그 → 메트릭 변환:
- request_id 기준의 샘플링 트레이스
- 에러 유형/스택트레이스 지표화
- 알림 정책:
- 짧은 급증(배포 직후)과 지속 문제를 구분
- 에러 버짓 기반(예: 월간 5xx 허용치) 알림
OpenTelemetry 권장:
- 자동 계측 + 사용자 정의 스팬
- Trace/Log 상호 링크(로그에 trace_id 포함)
런북(운영 가이드) 표준화
- 장애 인입 → 분류(500/502/503/504) → 영향도 평가 → 즉시 완화책
- 재현 스크립트(curl/hey) 저장소화
- 로그 쿼리 스니펫(서버/앱/DB) 공유
- 공용 체크리스트:
- 배포 여부/릴리스 노트
- 트래픽 급증/유입원
- 최근 구성 변경(ConfigMap/Secrets/Feature Flag)
- 외부 벤더 상태
- 종료 기준 정의: 5xx 비율 정상화, 원인 분석 보고, 재발 방지 항목 완료
재발 방지: 설계와 프로세스로 해결
- 코딩 관점:
- 철저한 입력 검증, 실패를 4xx로 변환
- 예외 핸들링 표준화, 사용자에게는 안전한 메시지
- 타임아웃/재시도/백오프/서킷브레이커 기본 탑재
- 스트리밍/청크 처리로 대용량 보호
- 배포 관점:
- 마이그레이션 파이프라인화(실패 시 자동 롤백)
- Canary + 자동 리그레션 알림(5xx 상승 자동 중단)
- 구성 Drift 탐지 및 비밀 관리 일원화
- 인프라 관점:
- 리소스 한계/버퍼/큐 길이 상한 설정
- 캐시 계층 강화(읽기 요청 흡수)
- 백프레셔(큐 넘침 방지)와 과부하 보호(503로 완곡 거절)
- 테스트/검증:
- 카나리 테스트, 혼합 트래픽에서의 Chaos/Latency 테스트
- 계약 기반 테스트(외부 API 스키마/타임아웃 시나리오)
실전 커맨드/스니펫 모음
- 5xx 비율 빠른 계산(Nginx access.log):
awk '{print $9}' /var/log/nginx/access.log | awk 'BEGIN{s=0;e=0}{if($1+0 >=500 && $1+0 <600)e++; s++}END{print "5xx:",e,"total:",s,"ratio:",(e/s)*100 "%"}'
- 가장 많은 500을 내는 업스트림:
awk '$9 ~ /500/ {print $1, $7, $8, $10}' /var/log/nginx/access.log | head
- gunicorn 워커 타임아웃 추적:
grep -i "Worker timeout" /var/log/app/app.log | tail
- PostgreSQL 연결 수:
SELECT state, count(*) FROM pg_stat_activity GROUP BY 1;
- 쿠버네티스 최근 재시작이 많은 파드:
kubectl get pods -A --sort-by='.status.containerStatuses[0].restartCount' | tail
케이스 스터디: 파일 업로드 API에서만 500 발생
증상:
- 10MB 이상 업로드 시 500, Nginx error_log에 “upstream prematurely closed connection”
조치:
- Nginx 설정 점검
client_max_body_size 50m;
proxy_read_timeout 180s;
proxy_buffering on;
- PHP-FPM
; php.ini
upload_max_filesize = 50M
post_max_size = 50M
max_execution_time = 180
- 애플리케이션
- 스트리밍 업로드 처리, 임시 파일 권한 확인
- 예외 시 500 대신 명확한 4xx/메시지 반환
- 재현 테스트
curl -vk -F "[email protected]" https://api.example.com/upload -H "X-Request-ID:test-up"
결과: 정상 처리, 로그에 request_id로 전 구간 추적 가능.
체크리스트: 장애 후 회고(Postmortem) 항목
- 장애 감지까지 걸린 시간, 원인 분류 속도
- 상관관계 ID/트레이싱 커버리지
- 모니터링 지표, 알림 임계치의 적정성
- 롤백/완화 속도, 고객 영향 최소화 여부
- 문서화/런북 업데이트, 자동화 도입 포인트
2026 업데이트: 현재 시점의 500 트러블슈팅
원문의 “로그 → 재현 → 원인별 시나리오” 절차는 변함없이 핵심입니다. 다만 관측성 스택과 배포 파이프라인이 바뀌며 500의 진단 속도를 크게 높일 수 있는 방법이 생겼습니다.
OpenTelemetry로 trace_id 상관관계를 표준화
원문의 “상관관계 ID” 개념은 이제 W3C Trace Context(traceparent) 와 OpenTelemetry로 표준화됐습니다.
- 게이트웨이·앱·DB 호출이 같은
trace_id를 공유하면, 500이 발생한 정확한 스팬(어느 함수/쿼리/외부 호출)을 즉시 지목할 수 있습니다. - 로그에
trace_id를 필드로 남기면(구조화 로깅 JSON), 로그·트레이스·메트릭을 한 번에 교차 조회할 수 있습니다.
eBPF로 코드 수정 없이 5xx 관측
Cilium/Hubble·Pixie 같은 eBPF 도구는 애플리케이션을 건드리지 않고 커널 레벨에서 HTTP 상태 코드를 수집합니다. 레거시 서비스나 서드파티 바이너리에서 500이 어느 파드/연결에서 시작됐는지 빠르게 좁힐 때 특히 유용합니다.
AI 보조 로그 분석
장문의 스택트레이스·다중 서비스 로그를 LLM으로 요약·원인 가설화하는 흐름이 보편화됐습니다.
- 활용: 스택트레이스 + 최근 배포 diff + 관련 로그를 함께 제시해 “가능한 원인 Top 3”를 빠르게 추리기.
- 주의: 로그에 PII/시크릿이 포함될 수 있으므로 마스킹 후 사용. 최종 판단은 사람이 검증.
공급망·구성 드리프트(현대적 500의 단골)
컨테이너·CI/CD가 보편화되며 “코드는 그대론데 환경이 달라서” 나는 500이 늘었습니다.
- 의존성/락파일 드리프트: 빌드 시점과 런타임 이미지의 패키지 버전 불일치. 락파일 고정·재현 가능한 빌드로 방지.
- 시크릿/환경변수 누락: 새 환경에 키가 안 들어가 부팅 직후 500. 12-factor 구성 검증을 배포 게이트에 포함.
- 만료된 토큰/인증서: 외부 API 키·mTLS 인증서 만료 → 의존성 호출 실패로 500. 만료 모니터링 필수.
- 마이그레이션/스키마 드리프트: 코드는 새 컬럼을 기대하는데 마이그레이션 미적용. 배포 순서(마이그레이션 → 코드)와 하위호환을 강제.
사용자에게 스택트레이스를 절대 노출하지 않기(보안)
운영 환경에서는 디버그 모드를 끄고(예: Laravel APP_DEBUG=false, Django DEBUG=False) 일반화된 오류 페이지를 보여주세요. 상세 원인은 서버 로그에만 남깁니다. 스택트레이스 노출은 정보 유출 취약점입니다.
자주 묻는 질문 (FAQ)
Q. 500과 502는 어떻게 다른가요? 500은 애플리케이션이 정상적으로 연결됐지만 내부에서 예외/오류가 난 경우이고, 502는 게이트웨이가 업스트림으로부터 잘못된 응답/끊긴 연결을 받은 경우입니다. 500은 앱 로그(스택트레이스)부터, 502는 프록시·연결부터 봅니다.
Q. 사용자에게는 무엇이 보이나요? 대개 “500 Internal Server Error” 또는 일반 오류 페이지만 보입니다. 구체적 원인은 서버 로그에 있으며, 사용자 화면에 상세 오류가 보인다면 디버그 모드가 켜져 있다는 위험 신호입니다.
Q. 로그는 어디부터 봐야 하나요?
① 웹서버 에러 로그(Nginx/Apache) → ② 애플리케이션 로그(스택트레이스) → ③ 시스템/컨테이너 이벤트(OOMKilled 등) → ④ 외부 의존성(DB·API) 순으로 좁히세요. trace_id가 있으면 한 번에 교차 조회됩니다.
Q. 로컬에서는 재현이 안 됩니다.
대개 환경 차이(시크릿·버전·권한·데이터)입니다. 운영과 동일한 컨테이너 이미지/환경변수로 스테이징에서 재현하고, 실패한 정확한 요청을 trace_id로 추적하세요.
Q. 간헐적 500은 어떻게 잡나요? 메모리 부족(OOM), 커넥션 풀 고갈, 외부 API 타임아웃, 특정 입력에서만 터지는 예외가 흔합니다. 메트릭(메모리/FD/풀 사용률)과 트레이싱으로 패턴(시간대·엔드포인트·입력)을 찾으세요.
마무리: 500을 “예외”에서 “관리 가능한 사건”으로
500 Internal Server Error는 통제 불가능한 사고가 아닙니다. 체계적 추적(상관관계 ID), 일관된 로그/트레이스, 재현 가능한 테스트, 표준화된 런북만 갖추면, 대부분의 500은 수 분 내 영향 범위를 줄이고 수 시간 내 근본 원인을 찾아 해결할 수 있습니다. 2024년의 복잡한 인프라에서도 원칙은 동일합니다.
- 어디서 500이 생성되는가? → 경계부터 좁히기
- 어떤 패턴의 요청에서만 발생하는가? → 접근/에러 로그 상관
- 시스템 지표는 무엇을 말하는가? → 리소스/타임아웃/의존성
- 재현 가능한가? → 명령/스크립트로 증거 고정
- 영구 해결/재발 방지는? → 설계·배포·관측 개선
이번 가이드를 팀의 표준으로 삼아, 다음 500이 왔을 때 더 빠르고 차분하게 대응해 보세요.