웹 개발
페이지 로딩 속도가 갑자기 느려졌을 때 시작하는 방법
운영 중 페이지가 버벅거리기 시작했을 때, 어디서부터 디버깅을 시작할지 결정하는 체크리스트.
어제는 빨랐던 페이지가 오늘은 느려졌다. 무언가 바뀌었는데 뭔지 모른다. 사용자 불평이 늘어난다.
이런 경우 고칠 게 정말 많아 보인다. 하지만 순서대로 확인하면, 대부분 몇 가지 원인 중 하나다.
1단계: 로컬에서 재현 가능한가
# 같은 URL을 여러 번 방문
curl -w "Total: %{time_total}s\n" https://yoursite.com/page
# 또는 DevTools에서
# 네트워크 연결 속도 제한 (Throttling)
# F12 → Network → Slow 3G 시뮬레이션
로컬이 빠르면 운영 서버의 네트워크나 리소스 문제다. 로컬도 느리면 코드나 DB 쿼리 문제다.
2단계: 페이지의 어느 부분이 느린가
// DevTools Performance에서 기록
// F12 → Performance → 기록 시작 → 페이지 새로고침 → 기록 중단
// 또는 Core Web Vitals 측정
// LCP (Largest Contentful Paint): 가장 큰 요소가 보일 때까지
// FID (First Input Delay): 첫 입력 지연
// CLS (Cumulative Layout Shift): 레이아웃 변동
Performance 플레임 차트에서:
- Network: 리소스 다운로드 (이미지, JS, CSS)
- Scripting: JavaScript 실행
- Rendering: 레이아웃 계산, 페인트
어느 구간이 긴가 본다.
3단계: Network 탭에서 느린 리소스 확인
DevTools Network 탭
→ 이미지, JS, CSS 파일 확인
→ 크기가 크거나 로드 시간이 긴 파일 찾기
특정 파일이 갑자기 커졌거나, 새로운 파일이 추가됐다면 그게 범인일 수 있다.
# 배포된 파일 크기 확인
ls -lh dist/
ls -lh .next/static/
빌드 결과물이 예상보다 크다면 bundler 설정을 봐야 한다.
4단계: 서버 응답 시간 확인
# Time to First Byte (TTFB)
curl -w "TTFB: %{time_starttransfer}s\n" https://yoursite.com/page
TTFB가 1초 이상이면 서버가 느리다는 뜻이다.
서버 로그를 본다:
# 평균 요청 처리 시간
docker logs app | grep "ms" | tail -100
# 또는 application 성능 모니터링
# APM 도구 (DataDog, New Relic) 확인
특정 엔드포인트만 느린가, 아니면 전체가 느린가?
5단계: 데이터베이스 쿼리 확인
서버가 느려진 주요 원인은 DB 쿼리다:
// 쿼리 실행 시간 로깅
const start = Date.now()
const result = await db.query('SELECT * FROM posts')
const elapsed = Date.now() - start
console.log(`Query took ${elapsed}ms`)
만약 쿼리가 10초 이상 걸린다면:
- 인덱스가 없는가
- 데이터가 최근에 매우 늘어났는가
- DB 연결이 느린가
-- PostgreSQL
EXPLAIN ANALYZE SELECT * FROM posts WHERE user_id = 123;
-- 인덱스 생성
CREATE INDEX idx_posts_user_id ON posts(user_id);
6단계: 리소스 사용률 확인
# CPU
top -o %CPU
# 메모리
free -h
# 디스크
df -h
# 네트워크
iftop # 또는 nethogs
어느 리소스가 꽉 찼는가?
CPU 100%: 앱이 무거운 계산을 하거나, 무한 루프에 빠짐 메모리 80% 이상: 메모리 누수 또는 캐시가 커짐 디스크 90% 이상: 로그가 꽉 찼거나 DB가 커짐
7단계: 최근 변경사항 확인
# 어제와 오늘의 배포 내역
git log --oneline -20
# 또는 배포 플랫폼 히스토리
# Dokploy, Vercel 등에서 최근 배포 확인
패턴:
- 새 버전 배포 후 느려짐: 코드 변경
- 배포 안 했는데 느려짐: DB 용량 증가, 트래픽 증가, 외부 API 지연
8단계: 캐시 확인
# Redis 캐시 크기
redis-cli INFO stats
# 캐시 히트율
redis-cli INFO stats | grep hit
# 또는 캐시 플러시 후 재로드
redis-cli FLUSHALL
캐시가 커서 메모리 사용량이 늘어났을 수도 있다. 또는 캐시 히트율이 낮아서 DB 쿼리가 많아졌을 수도.
9단계: 트래픽 증가 확인
# 웹 서버 로그에서 요청 수
grep $(date +%d/%b/%Y) /var/log/nginx/access.log | wc -l
# 또는 모니터링 대시보드
# CloudFlare Analytics, AWS CloudWatch 확인
갑자기 사용자가 50배 늘어났다면, 당연히 느려진다. 이 경우 스케일링이 필요하다:
# Docker Swarm
docker service scale app=3
# Kubernetes
kubectl scale deployment app --replicas=3
10단계: 응급 조치
원인을 찾는 데 시간이 걸리면, 빠른 개선부터 한다:
# 1. 캐시 재시작
redis-cli FLUSHALL
redis-cli SHUTDOWN
# Redis 재시작
# 2. 오래된 로그 정리
find /var/log -type f -mtime +30 -delete
# 3. DB 최적화
VACUUM; # PostgreSQL
OPTIMIZE TABLE; # MySQL
# 4. CDN 캐시 초기화 (Cloudflare 등)
# 대시보드에서 캐시 삭제
# 5. 마지막 수단: 인스턴스 재시작
docker-compose restart
이 중 하나라도 하면 대부분 일시적으로 빨라진다. 그 사이 원인을 파악한다.
성능 저하 원인 순서 (통계)
- DB 쿼리 느림 (40%): 인덱스 없음, 데이터 폭증
- 메모리 부족 (30%): 캐시 커짐, 메모리 누수
- 트래픽 증가 (15%): 스케일링 필요
- 큰 리소스 (10%): 이미지, JS 번들 증가
- 외부 API 지연 (5%): 의존하는 서비스 느림
체크리스트 (5분)
curl -w "TTFB: %{time_starttransfer}s"- 서버 응답top -o %CPU- CPU/메모리- DevTools Performance - 병목 지점
git log -1- 최근 배포- DB 쿼리 로그 - 느린 쿼리
이 5가지만 확인하면, 대부분의 경우 원인을 찾을 수 있다.