핵심 챌린지
기술적 문제 해결 경험 3 가지.
1. Consumer N² 스케일링 문제
문제
SFU 아키텍처에서 참가자 수 증가 시 Consumer 가 기하급수적으로 증가.
Consumer 수 = 참가자 × (참가자 - 1) × 2(비디오 + 오디오) 10 명: 10 × 9 × 2 = 180 개 30 명: 30 × 29 × 2 = 1,740 개
원인 분석
P2P → SFU 전환 시 클라이언트 부하는 줄었으나, 서버 리소스 (메모리, CPU) 가 N² 비례 증가.
특히 30 명 1080P/30fps 테스트에서 Consumer 1,510 개 생성 → CPU 99% 도달.
해결
- Simulcast 적용: 3 단계 해상도 자동 조절 (100k/300k/900k bps)
- Consumer 지연 생성: 화면에 보이는 참가자만 구독
- 스펙업 가이드라인 도출: 인원별 필요 인스턴스 타입 정리
| 결과 | Before | After |
|---|---|---|
| 30 명 CPU | 99% | 65% (Simulcast) |
| 대역폭 | 1,272 Mbps | ~400 Mbps |
2. Producer 라이프사이클 설계
문제
화면 공유 시작 시 카메라 비디오가 사라짐. 카메라 + 화면 공유 동시 사용 불가.
원인 분석
- 카메라 비디오 사라짐
- → 화면 공유 Producer 가 카메라 Producer 를 덮어씀
- → 두 Producer 를 구분하지 못함
- → kind(video) 만으로 Producer 식별
- → 근본 원인: 초기 설계 시 비디오 트랙 1 개만 가정
mediasoup Producer 는 kind(audio/video) 로만 구분. 동일 kind 의 다중 스트림 시나리오 미고려.
해결
Producer 생성 시 appData 에 스트림 타입 메타데이터 추가:
// appData로 스트림 타입 구분
{
kind: "video",
appData: {
isScreenShare: true, // 카메라 vs 화면 공유 구분
socketId: "socket-123"
}
}| 결과 | Before | After |
|---|---|---|
| 동시 전송 | 불가 | 가능 |
| Producer 수 | 1 개 (충돌) | 2 개 (공존) |
Lessons
- 요구사항 확장 시 기존 식별자 체계 검토 필수.
- mediasoup
appData는 스트림 메타데이터 관리에 유용.
3. 이중 병목 구조 발견
문제
부하 테스트 결과의 비선형 현상:
- 참가자 3 배 증가 (10 명 → 30 명)
- Jitter 1.4 배만 증가 (2.1 초 → 3.0 초)
왜 3 배 증가했는데 Jitter 는 1.4 배만 증가했는가?
원인 분석
- Jitter 가 예상보다 적게 증가
- → 10 명 시점에서 이미 병목 발생
- → 네트워크 대역폭 초과 (434Mbps > 100Mbps baseline)
- → 30 명에서 CPU 도 포화 (99%)
- → 근본 원인: 1 차 병목 (네트워크) 이 2 차 병목 (CPU) 영향을 가림
| 시나리오 | 1 차 병목 | 2 차 병목 | Jitter |
|---|---|---|---|
| 10 명 | 네트워크 (포화) | CPU (50%) | 2.1 초 |
| 30 명 | 네트워크 (포화) | CPU (99%) | 3.0 초 |
네트워크가 먼저 포화되면 추가 트래픽이 드롭되어 CPU 병목 영향이 제한적으로 나타남.
해결
- 스펙업 시 네트워크 대역폭과 CPU 동시 고려
- 인스턴스 타입별 예상 수용 인원 가이드라인 도출
| 인스턴스 | 네트워크 | 예상 수용 |
|---|---|---|
| t3.small | ~100 Mbps | 2~3 명 |
| c5.large | 최대 10 Gbps | 10~15 명 |
| c5.xlarge | 최대 10 Gbps | 20~30 명 |
Lessons
- 성능 이슈는 단일 원인이 아닐 수 있음. 데이터 기반 의사결정 (추측 → 측정 → 분석).
구현된 최적화 현황
| 항목 | 상태 | 설명 |
|---|---|---|
| Simulcast | 완료 | 3 단계 해상도 자동 조절 |
| appData 스트림 구분 | 완료 | 카메라/화면 공유 동시 지원 |
| 트래픽 로거 | 완료 | getStats() 기반 실시간 메트릭 |
| Active Speaker 모드 | 미구현 | Consumer 수 감소 최적화 |
사용 디버깅 도구
| 도구 | 용도 |
|---|---|
chrome://webrtc-internals | ICE 상태, RTP 통계 |
producer.getStats() | Jitter, RTT, 패킷 손실 |
| 커스텀 트래픽 로거 | 세션별 메트릭 집계 |
| v8-profiler-next | Node.js CPU 프로파일 |