AV Chaos Monkey
Plataforma distribuida de ingeniería del caos para pruebas de carga en sistemas de videoconferencia. Simula más de 1500 participantes WebRTC con flujos H.264/Opus e inyecta picos de caos en la red para validar la resiliencia del sistema en condiciones degradadas.
Arquitectura
-
Pipeline de Procesamiento de Medios:
- FFmpeg convierte el video de entrada a H.264 Annex-B y Ogg/Opus al inicio
- NAL Reader analiza el flujo H.264 (SPS/PPS/IDR/Slices)
- Opus Reader extrae tramas de audio de 20 ms del contenedor Ogg
- Las tramas se almacenan en caché en memoria, compartidas entre todos los participantes (copia cero)
- Reduce la CPU en ~90% frente a la codificación por participante
-
Plano de Control:
- Servidor HTTP (:8080) gestiona el ciclo de vida de la prueba mediante API REST
- Spike Scheduler distribuye eventos de caos (even/random/front/back/legacy)
- Network Degrader aplica caos: pérdida de paquetes (1-25%), jitter (10-50 ms), reducción de tasa de bits (30-80%), caída de tramas (10-60%)
- La configuración de caos cargada se aplica al grupo de participantes
-
Grupo de Participantes:
- Particionado automático entre pods usando:
participant_id % total_partitions = partition_id
- Cada participante genera flujos RTP (PT=96 video, PT=111 audio)
- El ID del participante se incrusta en la cabecera de extensión RTP (ID=1)
- Tamaño del grupo: 1-100 (local), 100-500 (Docker), 500-1500 (Kubernetes)
-
Auto-Configuración de Kubernetes:
- Los pods detectan automáticamente el ID de partición desde el nombre del pod:
orchestrator-3 → PARTITION_ID=3
- Asignación de puertos:
base_port + (partition_id × 10000) + participant_index
- Ejemplo: Partición 0 usa 5000-14999, Partición 1 usa 15000-24999
- StatefulSet con 10 réplicas, cada una manejando ~150 participantes
- Recursos: 1-4 CPU, 2-4Gi de memoria por pod
- Se configura automáticamente según las especificaciones de la máquina anfitriona
-
Cadena de Relay UDP (solo Kubernetes):
Pods Orquestador (10×) → UDP :5000 → udp-relay Pod (Python)
→ TCP con prefijo de longitud :5001 → kubectl port-forward 15001:5001
→ tools/udp-relay (Go) → UDP :5002 → Su Receptor
- Por qué: kubectl port-forward solo soporta TCP, no UDP
- Relay en el clúster: Script Python agrega UDP de todos los pods, lo transmite como TCP con prefijo de longitud de 2 bytes
- Relay local: Herramienta Go convierte el flujo TCP de vuelta a paquetes UDP
- Agrega 1500 flujos de participantes en una sola conexión
-
Infraestructura WebRTC:
- Coturn StatefulSet: 3 réplicas iniciales, HPA escala 1-10 según carga (~500 participantes/réplica)
- Servicio coturn-lb: Balancea el tráfico TURN entre réplicas
- webrtc-connector: Capa proxy opcional (Deployment + HPA 2-10 réplicas), maneja señalización SDP
- Modo Docker: Contenedor Coturn único para pruebas locales
- Puertos: 3478 (TURN), 49152-65535 (rango de relay)
- Credenciales: webrtc/webrtc123
-
Integración del Cliente:
- Receptor UDP: Recibe el flujo RTP agregado de todos los participantes a través de la cadena de relay
- Receptor WebRTC: Establece conexiones WebRTC 1:1 mediante intercambio SDP a través de servidores TURN
- Ambos reenvían a su sistema de videollamada bajo prueba (SFU/MCU/Mesh)
-
Stack de Observabilidad (Opcional):
- Prometheus: Recolecta el endpoint
/metrics de todos los pods orquestadores cada 5s
- Grafana: Visualiza métricas mediante un panel preconfigurado (admin/admin)
- Métricas expuestas: número de participantes, paquetes enviados, bytes enviados, picos activos, % de pérdida de paquetes, jitter ms, puntuación MOS
- Acceso: Prometheus en :30090, Grafana en :30030 (NodePort)
- Pods orquestadores anotados para autodescubrimiento:
prometheus.io/scrape: "true"
Conceptos Clave
Simulación de Participantes
Cada participante virtual genera flujos de medios reales:
- Video: Unidades NAL H.264 de archivos de video reales, empaquetadas según RFC 6184
- Audio: Tramas Opus de contenedores Ogg, empaquetadas según RFC 7587
- RTP: Cabeceras conformes a estándares con extensiones de ID de participante
- Temporización: Temporización precisa de trama (30fps video, paquetes de audio de 20 ms)
Inyección de Caos
Cinco tipos de picos simulan condiciones de red del mundo real:
- Pérdida de Paquetes: Descarta paquetes RTP en la capa de aplicación (1-100%)
- Jitter de Red: Añade variación de latencia (latencia base + jitter gaussiano)
- Reducción de Tasa de Bits: Limita la codificación de video (30-80% de reducción)
- Caída de Tramas: Omite tramas de video (10-60% de caída)
- Limitación de Ancho de Banda: Limita el rendimiento total
Estrategias de Distribución
Los picos se distribuyen a lo largo de la duración de la prueba mediante estrategias configurables:
- Even: Espaciado uniforme con jitter (carga predecible)
- Random: Temporización impredecible (caos realista)
- Front-loaded: Picos densos al inicio (prueba de recuperación)
- Back-loaded: Línea base seguida de caos (prueba comparativa)
- Legacy: Temporizador de intervalo fijo (inyección en tiempo de ejecución)
Particionado
Los despliegues en Kubernetes utilizan particionado de participantes para escalado horizontal:
- Cada pod maneja
participant_id % total_partitions == partition_id
- Asignación de puertos:
base_port + (partition_id * 10000) + participant_index
- Distribución automática de carga entre 1-10 pods
- Escala a más de 1500 participantes (150 por pod)
Ejecución del Sistema
1. Desarrollo Local (Go Nativo)
Mejor para: Desarrollo, depuración, pruebas a pequeña escala (1-100 participantes)
# Iniciar orquestador
go run cmd/main.go
# En otra terminal: Iniciar receptor UDP
go run examples/go/udp_receiver.go 5002
# Editar config/config.json para establecer num_participants: 10
# Ejecutar prueba de caos
go run tools/chaos-test/main.go -config config/config.json
Qué sucede:
- Un solo proceso orquestador en
:8080
- Los participantes envían UDP a
127.0.0.1:5002
- Los picos de caos se inyectan mediante API HTTP
- Métricas en tiempo real mostradas cada 2s
Configuración (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
}
}
2. Docker Compose (Contenerizado)
Mejor para: Pruebas aisladas, CI/CD, pruebas a escala mediana (100-500 participantes)
Requisitos previos:
- Docker Desktop con asignación de memoria de 8-16 GB
docker-compose instalado
# Construir e iniciar contenedor orquestador
./scripts/start_everything.sh build
# En otra terminal: Iniciar receptor UDP
go run examples/go/udp_receiver.go 5002
# Editar config/config.json para establecer num_participants: 100
# Ejecutar prueba de caos (apunta al contenedor)
go run tools/chaos-test/main.go -config config/config.json
Límites de recursos (editar docker-compose.yaml):
services:
orchestrator:
deploy:
resources:
limits:
cpus: "14.0"
memory: 6G # Aumentar para más participantes
Guía de escalado:
| Memoria Docker | Participantes Máximos | Núcleos CPU |
|---|
| 8 GB | ~100 | 4 |
| 16 GB | ~250 | 8 |
| 24 GB | ~400 | 12 |
| 32 GB | ~500 | 14 |