web/socket dev 배포 후 부하·병목 진단 실행 계획
마지막 업데이트 2026-07-22
결론: EC2에 무작정 부하를 먼저 주기보다, Grafana/Prometheus/Loki로 정상 기준선을 먼저 잡고 그 뒤 같은 시나리오를 단계적으로 증폭해야 병목을 정확히 분리할 수 있다.
LogRocket은 클라이언트 증상과 사용자 세션 재현을 확인하는 보조 축이다. 서버 병목의 1차 판단 기준은 /metrics, mediasoup/Redis/ffmpeg 지표, Loki JSON 로그다.
전체 실행 흐름
배포 확인
web/socket dev URL, health, metrics, rooms, workers/stats를 확인한다.
정상 기준선
1개 수업 흐름으로 CPU/RSS/event loop/Redis/mediasoup/LogRocket 기준값을 잡는다.
계층별 부하
HTTP, Socket 이벤트, 실제 브라우저 WebRTC를 분리해 병목 위치를 좁힌다.
판정
p95/p99, worker CPU, Redis latency, ffmpeg 수, 종료 후 자원 회수를 매트릭스로 판정한다.
개선 루프
누락 지표 보강 → 병목 수정 → 동일 부하 재실행으로 before/after를 확정한다.
관측 우선 vs 부하 우선
권장: 관측 기준선 먼저
- 정상 1세션의 지표 범위를 알아야 부하 결과를 해석할 수 있다.
- web, socket, Redis, mediasoup, 브라우저 문제가 섞이는 것을 줄인다.
- LogRocket 세션과 Loki 로그를
roomId,peerId,sessionId로 맞출 수 있다.
비권장: 바로 대량 부하
- 외부 API 대기, 브라우저 fake media, Redis latency, SFU CPU가 한 번에 섞인다.
- 원인 대신 “EC2가 느리다”는 결론만 남기 쉽다.
- OpenAI/Typecast 비용과 rate limit 영향이 병목처럼 보일 수 있다.
진단 데이터 흐름
배포 후 첫 체크리스트
/api/health/metrics- HTTP p95/p99
ppi_web_external_operation_duration_seconds
/health/metrics/workers/stats/rooms,/debug/redis-state
- LogRocket identify 정상 여부
- guest 네트워크 알림
- WebRTC getStats
- 브라우저 콘솔 오류
부하 시나리오 스케일
목표 동시 수업 수가 확정되지 않은 상태에서는 5/10/20 rooms ramp로 시작한다. 운영 목표가 정해지면 목표치의 1.2~1.5배까지 검증한다.
부하 계층별 실행 방법
1. HTTP/API 부하
k6 또는 autocannon으로 web API를 먼저 분리 측정한다.
- 대상: 로그인 없는 read API,
/api/health, 주요 dashboard API - 관측: HTTP p95/p99, 5xx, Next process CPU/RSS
- 주의: OpenAI/Typecast 유료 API는 별도 소수 E2E만 실행
2. Socket signaling 부하
socket.io-client 스크립트로 room 생성, host/guest join, toggle, reconnect, disconnect를 반복한다.
- 관측: connected clients, rooms, peers, Redis op latency
- 핵심: ack latency와 event error counter가 없으면 먼저 보강
- 목표: SFU 미디어 전 단계의 서버 이벤트 병목 분리
3. WebRTC/SFU 부하
Playwright + Chrome fake media로 실제 host/guest 브라우저를 띄워 mediasoup을 통과시킨다.
- 관측: mediasoup worker CPU, transports, producers, consumers
- 추가: 화면공유, 녹화, 재접속, 종료 후 자원 회수
- 목표: 실제 수업 병목과 리소스 누수 확인
4. LogRocket 기반 증상 확인
서버 지표와 브라우저 세션을 같은 시간대와 room context로 맞춘다.
- 서버 지표 정상 + LogRocket 오류 증가: 클라이언트/네트워크 쪽
- 서버 지표 상승 + LogRocket 끊김 증가: 서버 병목 가능성 높음
- 이슈 재현 링크는 분석용으로만 쓰고 병목 확정 근거는 metrics로 둔다.
병목 판정 매트릭스
| 신호 | 의심 지점 | 확인할 지표/로그 | 다음 조치 |
|---|---|---|---|
| web HTTP p95/p99 상승 + CPU 상승 | Next API, SSR, JSON 처리, DB/API 호출 전 처리 | http_request_duration_seconds, process CPU/RSS, route label |
느린 route 추적, 캐싱/배치, API handler 단축 |
| 외부 external operation 지연 상승 | OpenAI Realtime, Typecast, AWS/S3/DynamoDB, PPI API | ppi_web_external_operation_duration_seconds, Loki provider 로그 |
timeout, retry/backoff, queue, 동시성 제한 |
| socket mediasoup worker CPU 상승 | SFU 미디어 처리, worker 수/room 배치, 브라우저 media 부하 | ppi_mediasoup_worker_cpu_user, transports/producers/consumers |
worker/인스턴스 스케일, simulcast/encoding 정책 조정 |
| Redis Redis op p95 상승 | Redis hot key, round-trip 과다, cross-instance state 갱신 | ppi_socket_redis_op_duration_seconds, mismatch/redirect counters |
write coalescing, pipeline, hot-path Redis 호출 축소 |
| 누수 종료 후 gauge 미회수 | room/peer/router/transport/producer/consumer/ffmpeg 누수 | rooms, peers, ffmpeg_processes, /rooms |
disconnect/reaper/recording cleanup 경로 보강 |
| client 서버 정상 + LogRocket 오류 증가 | 브라우저, 디바이스 성능, 네트워크, 권한, getUserMedia | LogRocket event, WebRTC getStats, guest network alert | 클라이언트 로깅 보강, 기기별 정책 분리 |
우선 보강할 관측 지표
socket event별 ack latency histogram이 가장 먼저 필요하다. 현재는 HTTP/Redis/mediasoup 지표는 강하지만, Socket.io 이벤트 단위의 p95/p99가 부족해서 signaling 병목이 Redis인지 handler인지 broadcast인지 바로 분리하기 어렵다.
ppi_socket_event_duration_seconds{event,namespace,status}ppi_socket_event_total{event,namespace,status}ppi_socket_room_lifecycle_duration_seconds{phase,status}ppi_socket_broadcast_room_list_total{trigger}및 duration- 종료 후 자원 회수 검증용 room/peer/transport/producer/consumer diff 로그
실행 순서
- dev web/socket 배포 후 health와 metrics scrape 정상 여부를 확인한다.
- 1개 room 수업 흐름을 10-15분 실행해 정상 기준선을 저장한다.
- Grafana 패널을 고정한다: web HTTP, web external operation, socket clients/rooms/peers, mediasoup worker CPU, Redis latency, ffmpeg processes, process CPU/RSS/event loop.
- HTTP/API 부하를 먼저 실행해 web 병목을 독립적으로 본다.
- Socket signaling 부하를 실행해 Redis/handler/broadcast 병목을 본다.
- Playwright fake media로 실제 WebRTC/SFU 부하를 실행한다.
- 각 단계 종료 후 5분 안에 room/transport/producer/consumer/ffmpeg가 기준선으로 회수되는지 확인한다.
- 병목 후보를 하나만 고쳐 같은 시나리오를 재실행한다.
운영 주의사항
OpenAI Realtime, Typecast TTS, S3 업로드를 전체 부하에 무조건 섞으면 비용과 rate limit이 병목처럼 보인다. 전체 ramp에서는 mock 또는 제한된 subset으로 두고, 실제 외부 provider 포함 E2E는 별도 소수 케이스로 분리한다.
- dev 브랜치 EC2와 socket loadtest EC2를 구분한다. 이미
deploy-socket-loadtest.yml가 있으므로 socket 단독 부하는 이 경로를 우선 사용한다. - Redis는 stage/key prefix가 중요하다. dev/prod/loadtest key 충돌 여부를
/debug/redis-state와 prefix 설정으로 먼저 확인한다. - 테스트 중 Grafana 시간 범위를 고정하고, 각 시나리오 시작/종료 시각을 로그에 남긴다.
- 부하 생성기 자체 CPU가 병목이 되지 않도록 runner와 대상 EC2를 분리한다.
성공 기준
| 항목 | 통과 기준 |
|---|---|
| 재현성 | 같은 시나리오에서 같은 지표가 반복 상승한다. |
| 분리성 | web, socket signaling, SFU media, client/network 중 하나로 병목을 좁힌다. |
| 회수성 | 종료 후 rooms/peers/transports/producers/consumers/ffmpeg가 기준선으로 내려온다. |
| 개선 검증 | 수정 전후 같은 부하에서 p95/p99 또는 CPU/RSS가 유의미하게 개선된다. |