AV Chaos Monkey
Распределенная платформа хаос-инжиниринга для нагрузочного тестирования систем видеоконференций. Симулирует 1500+ участников WebRTC с потоками H.264/Opus и инжектирует пики сетевого хаоса для проверки устойчивости системы в условиях деградации.
Архитектура
-
Конвейер обработки медиа:
- FFmpeg конвертирует входное видео в H.264 Annex-B и Ogg/Opus при запуске
- NAL Reader парсит поток H.264 (SPS/PPS/IDR/Слайсы)
- Opus Reader извлекает 20-мс аудиофреймы из контейнера Ogg
- Фреймы кэшируются в памяти, совместно используются всеми участниками (zero-copy)
- Снижает загрузку CPU на ~90% по сравнению с кодированием для каждого участника
-
Плоскость управления:
- HTTP-сервер (:8080) управляет жизненным циклом теста через REST API
- Планировщик пиков (Spike Scheduler) распределяет события хаоса (равномерные/случайные/с фронтальной загрузкой/с тыловой загрузкой/унаследованные)
- Сетевой деградатор (Network Degrader) применяет хаос: потеря пакетов (1-25%), джиттер (10-50 мс), снижение битрейта (30-80%), пропуск кадров (10-60%)
- Загруженная конфигурация хаоса применяется к пулу участников
-
Пул участников:
- Автоматически разделяется между подами по формуле:
participant_id % total_partitions = partition_id
- Каждый участник генерирует RTP-потоки (PT=96 видео, PT=111 аудио)
- ID участника встраивается в заголовок расширения RTP (ID=1)
- Размер пула: 1-100 (локально), 100-500 (Docker), 500-1500 (Kubernetes)
-
Автоконфигурация Kubernetes:
- Поды автоматически определяют ID раздела (partition ID) из имени пода:
orchestrator-3 → PARTITION_ID=3
- Выделение портов:
base_port + (partition_id × 10000) + participant_index
- Пример: Раздел 0 использует 5000-14999, Раздел 1 использует 15000-24999
- StatefulSet с 10 репликами, каждая обрабатывает ~150 участников
- Ресурсы: 1-4 CPU, 2-4 ГБ памяти на под
- Автоконфигурация на основе характеристик хост-машины
-
UDP-ретрансляционная цепочка (только Kubernetes):
Поды-оркестраторы (10×) → UDP :5000 → Под udp-relay (Python)
→ TCP с префиксом длины :5001 → kubectl port-forward 15001:5001
→ tools/udp-relay (Go) → UDP :5002 → Ваш приёмник
- Почему: kubectl port-forward поддерживает только TCP, не UDP
- Ретранслятор внутри кластера: Python-скрипт агрегирует UDP со всех подов, передаёт как TCP с 2-байтовым префиксом длины
- Локальный ретранслятор: Go-утилита преобразует TCP-поток обратно в UDP-пакеты
- Агрегирует потоки 1500 участников в одно соединение
-
Инфраструктура WebRTC:
- StatefulSet Coturn: 3 начальные реплики, HPA масштабирует от 1 до 10 в зависимости от нагрузки (~500 участников/реплика)
- Сервис coturn-lb: Балансирует TURN-трафик между репликами
- webrtc-connector: Дополнительный прокси-слой (Deployment + HPA 2-10 реплик), обрабатывает SDP-сигнализацию
- Режим Docker: Один контейнер Coturn для локального тестирования
- Порты: 3478 (TURN), 49152-65535 (диапазон ретрансляции)
- Учётные данные: webrtc/webrtc123
-
Интеграция с клиентом:
- UDP-приёмник: Получает агрегированный RTP-поток от всех участников через ретрансляционную цепочку
- WebRTC-приёмник: Устанавливает соединения WebRTC 1:1 через обмен SDP через TURN-серверы
- Оба перенаправляют в тестируемую систему видеозвонков (SFU/MCU/Mesh)
-
Стек наблюдаемости (опционально):
- Prometheus: Собирает метрики с эндпоинта
/metrics всех подов-оркестраторов каждые 5 с
- Grafana: Визуализирует метрики через предварительно настроенную панель (admin/admin)
- Доступные метрики: количество участников, отправленные пакеты, отправленные байты, активные пики, процент потери пакетов, джиттер, оценка MOS
- Доступ: Prometheus на :30090, Grafana на :30030 (NodePort)
- Поды-оркестраторы аннотированы для автообнаружения:
prometheus.io/scrape: "true"
Основные концепции
Симуляция участников
Каждый виртуальный участник генерирует реальные медиапотоки:
- Видео: NAL-единицы H.264 из реальных видеофайлов, пакетизированные по RFC 6184
- Аудио: Фреймы Opus из контейнеров Ogg, пакетизированные по RFC 7587
- RTP: Заголовки, соответствующие стандарту, с расширениями ID участника
- Тайминг: Фрейм-точный тайминг (30 кадр/с видео, 20 мс аудиопакеты)
Инжекция хаоса
Пять типов пиков симулируют реальные сетевые условия:
- Потеря пакетов: Отбрасывает RTP-пакеты на прикладном уровне (1-100%)
- Сетевой джиттер: Добавляет вариацию задержки (базовая + гауссов джиттер)
- Снижение битрейта: Ограничивает кодирование видео (снижение на 30-80%)
- Пропуск кадров: Пропускает видеокадры (10-60% пропуска)
- Ограничение пропускной способности: Ограничивает общую пропускную способность
Стратегии распределения
Пики распределяются по длительности теста с помощью настраиваемых стратегий:
- Равномерная (Even): Равномерные интервалы с джиттером (предсказуемая нагрузка)
- Случайная (Random): Непредсказуемое время (реалистичный хаос)
- С фронтальной загрузкой (Front-loaded): Частые пики в начале (тестирование восстановления)
- С тыловой загрузкой (Back-loaded): Базовый уровень, затем хаос (сравнительное тестирование)
- Унаследованная (Legacy): Таймер с фиксированным интервалом (инжекция во время выполнения)
Разделение на партиции
В развёртываниях Kubernetes используется разделение участников на партиции для горизонтального масштабирования:
- Каждый под обрабатывает
participant_id % total_partitions == partition_id
- Выделение портов:
base_port + (partition_id * 10000) + participant_index
- Автоматическое распределение нагрузки между 1-10 подами
- Масштабируется до 1500+ участников (150 на под)
Запуск системы
1. Локальная разработка (нативный Go)
Лучше всего для: Разработка, отладка, мелкомасштабные тесты (1-100 участников)
# Запуск оркестратора
go run cmd/main.go
# В другом терминале: Запуск UDP-приёмника
go run examples/go/udp_receiver.go 5002
# Отредактируйте config/config.json, установите num_participants: 10
# Запуск теста хаоса
go run tools/chaos-test/main.go -config config/config.json
Что происходит:
- Один процесс оркестратора на порту
:8080
- Участники отправляют UDP на
127.0.0.1:5002
- Пики хаоса инжектируются через HTTP API
- Метрики в реальном времени отображаются каждые 2 с
Конфигурация (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 (контейнеризированный)
Лучше всего для: Изолированное тестирование, CI/CD, средне-масштабные тесты (100-500 участников)
Предварительные требования:
- Docker Desktop с выделением 8-16 ГБ памяти
- Установленный
docker-compose
# Сборка и запуск контейнера оркестратора
./scripts/start_everything.sh build
# В другом терминале: Запуск UDP-приёмника
go run examples/go/udp_receiver.go 5002
# Отредактируйте config/config.json, установите num_participants: 100
# Запуск теста хаоса (нацелен на контейнер)
go run tools/chaos-test/main.go -config config/config.json
Ограничения ресурсов (редактируйте docker-compose.yaml):
services:
orchestrator:
deploy:
resources:
limits:
cpus: "14.0"
memory: 6G # Увеличьте для большего числа участников