
오디오/비디오 테스트를 위한 Chaos Monkey (webRTC 및 UDP)
분산 카오스 엔지니어링 플랫폼으로, 화상 회의 시스템의 부하 테스트를 수행합니다. H.264/Opus 스트림으로 1500명 이상의 WebRTC 참가자를 시뮬레이션하고 네트워크 카오스 스파이크를 주입하여 저하된 조건에서 시스템 복원력을 검증합니다.
미디어 처리 파이프라인:
컨트롤 플레인:
참가자 풀:
participant_id % total_partitions = partition_idKubernetes 자동 구성:
orchestrator-3 → PARTITION_ID=3base_port + (partition_id × 10000) + participant_indexUDP 릴레이 체인(Kubernetes 전용):
Orchestrator Pods (10×) → UDP :5000 → udp-relay Pod (Python)
→ Length-Prefixed TCP :5001 → kubectl port-forward 15001:5001
→ tools/udp-relay (Go) → UDP :5002 → Your Receiver
WebRTC 인프라:
클라이언트 통합:
관측 가능성 스택(선택 사항):
/metrics 엔드포인트를 5초마다 스크래핑prometheus.io/scrape: "true"각 가상 참가자가 실제 미디어 스트림을 생성:
다섯 가지 스파이크 유형으로 실제 네트워크 조건 시뮬레이션:
스파이크는 구성 가능한 전략을 사용해 테스트 기간에 분배:
Kubernetes 배포는 수평 확장을 위해 참가자 파티셔닝 사용:
participant_id % total_partitions == partition_id 처리base_port + (partition_id * 10000) + participant_index적합한 경우: 개발, 디버깅, 소규모 테스트(1-100명 참가자)
# Start orchestrator
go run cmd/main.go
# In another terminal: Start UDP receiver
go run examples/go/udp_receiver.go 5002
# Edit config/config.json to set num_participants: 10
# Run chaos test
go run tools/chaos-test/main.go -config config/config.json
동작:
:8080에서 단일 오케스트레이터 프로세스127.0.0.1:5002로 UDP 전송구성(config/config.json):
{
"base_url": "http://localhost:8080",
"media_path": "public/rick-roll.mp4",
"num_participants": 10,
"duration_seconds": 300,
"spikes": {
"count": 20,
"interval_seconds": 5,
"types": { "rtp_packet_loss": {...}, "network_jitter": {...} }
},
"spike_distribution": {
"strategy": "random",
"min_spacing_seconds": 5,
"jitter_percent": 15
}
}
적합한 경우: 격리된 테스트, CI/CD, 중간 규모 테스트(100-500명 참가자)
전제 조건:
docker-compose 설치# Build and start orchestrator container
./scripts/start_everything.sh build
# In another terminal: Start UDP receiver
go run examples/go/udp_receiver.go 5002
# Edit config/config.json to set num_participants: 100
# Run chaos test (targets container)
go run tools/chaos-test/main.go -config config/config.json
리소스 제한(docker-compose.yaml 편집):
services:
orchestrator:
deploy:
resources:
limits:
cpus: "14.0"
memory: 6G # Increase for more participants
확장 가이드:
| Docker 메모리 | 최대 참가자 | CPU 코어 |
|---|---|---|
| 8 GB | ~100 | 4 |
| 16 GB | ~250 | 8 |
| 24 GB | ~400 | 12 |
| 32 GB | ~500 | 14 |
적합한 경우: 대규모 테스트(500-1500명 참가자), 수평 확장, 프로덕션 검증
전제 조건:
# Nix provides: Go, Docker, kubectl, kind, ffmpeg
nix develop
# Or use direnv for auto-activation
echo "use flake" > .envrc
direnv allow
# Auto-deploy with optimal settings (detects system resources)
./scripts/start_everything.sh run -config config/config.json
# Or specify custom media files
./scripts/start_everything.sh run --media=path/to/video.mp4 -config config/config.json
동작:
kubectl port-forward 설정옵션 A: UDP 수신기(Kubernetes에 권장)
# Receives aggregated stream from all 1500 participants
go run ./examples/go/udp_receiver.go 5002
옵션 B: WebRTC 수신기(다중 참가자)
# Connect to up to 150 participants via WebRTC
go run ./examples/go/webrtc_receiver.go http://localhost:8080 <test_id> 150
아키텍처 흐름:
10개 파드에 걸친 1500명 참가자
→ 각 파드: 150명 참가자
→ participant_id % 10으로 파티셔닝
→ 모두 udp-relay:5000으로 UDP 전송
→ UDP 릴레이가 집계 → TCP :5001
→ kubectl port-forward 15001:5001
→ 로컬 릴레이가 TCP를 UDP :5002로 변환
→ 수신기가 1500개 스트림 모두 수신
참고: start_everything.sh 스크립트가 자동으로 설정:
# Build and load image
docker build -t chaos-monkey-orchestrator:latest .
kind load docker-image chaos-monkey-orchestrator:latest
# Deploy
kubectl apply -f k8s/orchestrator/orchestrator.yaml
kubectl apply -f k8s/udp-relay/udp-relay.yaml
# Wait for pods
kubectl wait --for=condition=ready pod -l app=orchestrator --timeout=300s
# Port-forward UDP relay
kubectl port-forward udp-relay 15001:5001 &
# Start local TCP→UDP relay
go run tools/udp-relay/main.go &
# In another terminal: Start receiver
go run ./examples/go/udp_receiver.go 5002
# In another terminal: Run chaos test
go run tools/chaos-test/main.go -config config/config.json
# Delete Kubernetes resources
./scripts/cleanup.sh
# Or delete entire cluster
kind delete cluster --name av-chaos-monkey
# Build for Linux x86_64 (most common)
nix build .#packages.x86_64-linux.av-chaos-monkey
# Build for ARM64 (Raspberry Pi, AWS Graviton)
nix build .#packages.aarch64-linux.av-chaos-monkey
# Build for macOS Intel
nix build .#packages.x86_64-darwin.av-chaos-monkey
# Build for macOS Apple Silicon
nix build .#packages.aarch64-darwin.av-chaos-monkey
# Binary location
./result/bin/main
# Create test
POST /api/v1/test/create
{
"test_id": "optional_id",
"num_participants": 100,
"video": {...},
"audio": {...},
"duration_seconds": 600,
"spikes": [...],
"spike_distribution": {
"strategy": "even",
"min_spacing_seconds": 5,
"jitter_percent": 15
}
}
# Start test
POST /api/v1/test/{test_id}/start
# Get metrics
GET /api/v1/test/{test_id}/metrics
# Stop test
POST /api/v1/test/{test_id}/stop
# Get SDP offer
GET /api/v1/test/{test_id}/sdp/{participant_id}
# Set SDP answer
POST /api/v1/test/{test_id}/sdp/{participant_id}
{"sdp_answer": "v=0..."}
# Inject spike
POST /api/v1/test/{test_id}/spike
{
"spike_id": "unique_id",
"type": "rtp_packet_loss",
"duration_seconds": 30,
"participant_ids": [1001, 1002],
"params": {"loss_percentage": "15"}
}
| 유형 | 매개변수 | 효과 |
|---|---|---|
rtp_packet_loss | loss_percentage (0-100) | RTP 계층에서 패킷 드롭 |
network_jitter | base_latency_ms, jitter_std_dev_ms | 지연 변동 추가 |
bitrate_reduce | new_bitrate_kbps | 비디오 인코딩 제한 |
frame_drop | drop_percentage (0-100) | 비디오 프레임 건너뜀 |
bandwidth_limit | bandwidth_kbps | 총 처리량 제한 |
{
"spike_distribution": {
"strategy": "even",
"min_spacing_seconds": 5,
"jitter_percent": 15,
"respect_min_offset": true
}
}
# Provided receiver with RTP parsing
go run examples/go/udp_receiver.go 5002
출력:
Listening for RTP packets on UDP port 0.0.0.0:5002
Packet #100 from 127.0.0.1:xxxxx:
Participant ID: 1001
Payload Type: 96 (H.264 video)
Sequence: 1234
Timestamp: 90000
SSRC: 1001000
Payload Size: 1200 bytes
═══════════════════════════════════════════════════════════
PACKET STATISTICS
═══════════════════════════════════════════════════════════
Duration: 60s
Total Packets: 180000 (3000 pkt/s)
Total Bytes: 450 MB (60 Mbps)
Media Type Breakdown:
Video (H.264): 120000 packets (66.7%)
Audio (Opus): 60000 packets (33.3%)
Unique Streams (SSRCs): 1500
Unique Participants: 1500
# Single participant
go run ./examples/go/webrtc_receiver.go http://localhost:8080 <test_id>
# Multiple participants (up to 150)
go run ./examples/go/webrtc_receiver.go http://localhost:8080 <test_id> 150
# Example with actual test ID
go run ./examples/go/webrtc_receiver.go http://localhost:8080 chaos_test_1770831684 150
참고: WebRTC는 1:1 연결이 필요합니다. Kubernetes의 경우 모든 참가자를 자동으로 집계하는 UDP 수신기를 사용하세요.
RTP 패킷 형식:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Extension ID=1 | Length=4 | Participant ID (uint32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| H.264/Opus Payload |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
페이로드 유형:
96: H.264 비디오(RFC 6184)111: Opus 오디오(RFC 7587)참가자 ID 추출:
// Extension bit set?
if (packet[0] & 0x10) != 0 {
offset := 12 + int(packet[0]&0x0F)*4 // Skip CSRC
extID := binary.BigEndian.Uint16(packet[offset:])
if extID == 1 {
participantID := binary.LittleEndian.Uint32(packet[offset+4:])
}
}
| 참가자 수 | 메모리 | CPU | 대역폭 |
|---|---|---|---|
| 100 | 2GB | 2 코어 | 250 Mbps |
| 500 | 6GB | 8 코어 | 1.2 Gbps |
| 1000 | 12GB | 16 코어 | 2.5 Gbps |
| 1500 | 18GB | 24 코어 | 3.7 Gbps |
참가자당(1280x720@30fps + Opus):
# Exposed on /metrics endpoint
av_chaos_monkey_participants_total
av_chaos_monkey_packets_sent_total
av_chaos_monkey_bytes_sent_total
av_chaos_monkey_spikes_active
av_chaos_monkey_packet_loss_percent
av_chaos_monkey_jitter_ms
# Docker Mode: Start monitoring stack
docker-compose --profile monitoring up
# Kubernetes Mode: Deploy monitoring
kubectl apply -f k8s/monitoring/prometheus-rbac.yaml
kubectl apply -f k8s/monitoring/prometheus.yaml
kubectl apply -f k8s/monitoring/grafana.yaml
# Access Grafana
# Docker: http://localhost:3000
# Kubernetes: http://localhost:30030 (NodePort)
# Default credentials: admin/admin
# Access Prometheus
# Docker: http://localhost:9091
# Kubernetes: http://localhost:30090 (NodePort)
Kubernetes 자동 발견:
prometheus.io/scrape: "true" 어노테이션/metrics를 5초마다 스크래핑# Get test metrics
curl http://localhost:8080/api/v1/test/{test_id}/metrics | jq
# Output
{
"aggregate": {
"total_frames_sent": 45000,
"total_packets_sent": 180000,
"total_bitrate_kbps": 250000,
"avg_jitter_ms": 12.5,
"avg_packet_loss": 2.3,
"avg_mos_score": 4.1
}
}
# Check UDP target configuration
kubectl logs orchestrator-0 | grep "UDP transmission enabled"
# Verify UDP relay is running
kubectl get pod udp-relay
# Check port-forward
ps aux | grep "kubectl port-forward"
# Test UDP connectivity
nc -u -z localhost 5002
# Check TURN server
kubectl get svc coturn-lb
# Verify ICE candidates
kubectl logs orchestrator-0 | grep "ICE"
# Test TURN connectivity
turnutils_uclient -v -u webrtc -w webrtc123 <turn-server>:3478
# Check participant count per pod
kubectl exec orchestrator-0 -- curl -s http://localhost:8080/api/v1/test/{test_id}/metrics | jq '.participants | length'
# Scale down participants or increase pod count
go run tools/k8s-start/main.go -replicas 10 -participants 1000
# Increase Docker memory (Docker Desktop)
# Settings → Resources → Memory → 16GB
단일 UDP 소켓은 커널 버퍼 오버플로 없이 3000개 이상의 동시 스트림을 처리할 수 없습니다. 해결 방법:
setsockopt(SO_RCVBUF, 8MB)BSD 3-Clause License
기여를 환영합니다! 주요 영역: