Нагрузочные тесты IoT
Контур: устройство → wss (EMQX) → бридж → SQS iot-telemetry → consumer → PG → API.
Запуск
cd loadtests
python3 -m loadtests.run <scenario> [опции]
# или из корня репо:
python3 -m loadtests.run <scenario> [опции]
Требования: Python 3.10+, paho-mqtt (pip install paho-mqtt).
Конфигурация через env (дефолты — прод):
| Env | Дефолт |
|---|---|
IOT_API |
https://iot.containerk8s.dev.nubes.ru |
IOT_WS |
wss://exqx.containerk8s.dev.nubes.ru/mqtt |
IOT_NS_PREFIX |
lt |
IOT_CLEANUP |
1 (удалять созданные тестом устройства) |
Тест сам регистрирует устройства через API (JWT структурный) в namespace
lt_<run-id> и удаляет их после прогона при IOT_CLEANUP=1.
Сценарии
| Сценарий | Что проверяет |
|---|---|
baseline |
Равномерная нагрузка: потери/дубли/задержка (p50/p95/p99) доставки в PG. |
burst |
Всплеск xN: рост очереди и время восстановления (recovery). |
large-payload |
Payload до ~900KB (лимит EMQX 1MB). |
reconnect-storm |
Периодические разрывы соединений (эмуляция edge-разрывов ~150с), QoS1. |
multitenant |
Много namespace: задержка первого сообщения (EnsureTenantDB). |
acl-violation |
Публикация в чужой топик → EMQX должен рвать сессию. |
auth-neg |
Неверный пароль → CONNACK 4, неизвестный юзер → CONNACK 5. |
api-crud |
Нагрузка на CRUD устройств (POST/GET/DELETE). |
telemetry-query |
Нагрузка на чтение телеметрии. |
soak |
Длительный прогон с периодическими срезами sent/delivered. |
Примеры:
python3 -m loadtests.run baseline --devices 50 --rate 2 --duration 120 --qos 0
python3 -m loadtests.run burst --devices 100 --rate 1 --burst-mult 10 --duration 30
python3 -m loadtests.run reconnect-storm --devices 100 --rate 1 --reconnect-every 30 --duration 300
python3 -m loadtests.run multitenant --tenants 20 --devices-per-tenant 3
python3 -m loadtests.run api-crud --threads 10 --iterations 20
python3 -m loadtests.run telemetry-query --threads 10 --iterations 50 --query-limit 100
python3 -m loadtests.run soak --devices 50 --rate 1 --duration 3600 --slice-sec 300
Ограничения
- SQS-лимит 256KB на сообщение (shared-sqs отклоняет:
InvalidParameterValue message size exceeds the limit) → payload устройств ≤ ~250KB с учётом envelope. Бридж дропает oversize с логомpayload too large for SQS. EMQX пропускает до 1MB, но узким местом конвейера является SQS. - API отдаёт максимум 1000 строк телеметрии на запрос; шлюз платформы
рвёт ответы >~15КБ (баг MSS/MTU, тикет Nubes) → верификатор ходит
страницами по 50 (
offset). Большие страницы НЕ использовать. - Задержка =
ts(PG) - sent_at - skew; skew калибруется первым сообщением (часы тест-машины и PG могут расходиться). - Consumer long-poll до ~20с → после публикаций нужна пауза перед сверкой (встроена в сценарии).
Критерии успеха (базовые)
baseline: loss_rate = 0, duplicates = 0, p99 < 10с при ≤100 msg/s.burst: recovery < 120с после конца пика.reconnect-storm: loss_rate < 0.01 (QoS1), forced_reconnects > 0.acl-violation: foreign_accepted = 0.auth-neg: rc = 4 и rc = 5.soak: delivered растёт монотонно, провалов нет.
Тесты с отключением сервисов (вручную, нужен kubectl с ВМ)
Снаружи отключить SQS/PG нельзя — их блокируют на кластере:
- SQS-outage (обрыв бриджа): заблокировать egress монолита к shared-sqs
network policy или
kubectl delete endpoints— 3 минуты, затем восстановить; метрики: ошибки SendMessage в логах бриджа, время восстановления доставки. (Известная проблема: SendMessage в handler блокирует MQTT-поток — см. HISTORY секция 31, Sonnet-ревью, находка №1.) - PG-outage:
kubectl -n <pg-ns> scale deployment postgresqlk8s --replicas=0на 5 минут; метрики: глубина SQS (ApproximateNumberOfMessages), дубли после восстановления (visibility timeout 30с — см. находку №2 ревью).
Оба теста — ТОЛЬКО на стенде, не на проде.
Что гонять на проде
Умеренно (безопасно): baseline (≤100 msg/s), auth-neg, acl-violation,
api-crud, telemetry-query, multitenant (≤20 тенантов).
Осторожно (off-peak): burst (x10 кратко), reconnect-storm (≤100 устройств),
large-payload (≤5 устройств).
Не на проде: SQS-outage, PG-outage, soak >1ч с высоким rate.