diff --git a/README.md b/README.md index 34d8ca9..6f6012e 100644 --- a/README.md +++ b/README.md @@ -249,3 +249,23 @@ curl -k -X PUT "https://stend.4mont.ru/api/admin/users/2/acl" \ - Нет отдельной UI-админки (есть admin API). - TTL неактивности основан на heartbeat runtime-страницы. - Для production стоит добавить Alembic-миграции, rate limiting и централизованный логинг. + +## 8. Нагрузочное тестирование (актуально на 2026-04-24) + +В проекте подтвержден рабочий плавный профиль нагрузки без резкого burst: +- +1 пользователь в минуту; +- целевой online: 20 пользователей; +- каждый запускает 2 WEB-сервиса (termidesk и vmmanager). + +Результат прогона 20x2: +- логин и открытие сервисов: 100% успешных проверок; +- HTTP 5xx в тесте: 0; +- достигнуто 40 ACTIVE WEB-сессий (20 + 20). + +Важно для повторения теста: +1. Перед прогоном временно увеличьте idle timeout (SESSION_IDLE_SECONDS) и пересоздайте WEB-пул, чтобы слоты получили новый IDLE_TIMEOUT. +2. Параллельно собирайте метрики хоста (uptime/free/df/docker stats) в файл. +3. После прогона проверяйте согласованность: ACTIVE-сессии в БД vs реально существующие portal-webpool-* контейнеры. + +Замеченный риск: +- при агрессивном авторасширении/сжатии WEB-пула возможны ACTIVE-сессии, привязанные к уже удаленным слотам. diff --git a/docs/PROJECT_CONTEXT.md b/docs/PROJECT_CONTEXT.md index 69c5ab5..68b5607 100644 --- a/docs/PROJECT_CONTEXT.md +++ b/docs/PROJECT_CONTEXT.md @@ -355,3 +355,138 @@ git push https://ruslan%40ipcom.su:utOgbZ09ruslan@git.ruslan.xyz/ruslan/Stend_mo 4. Операционная польза: - Быстрее диагностируются причины `504`/обрывов/закрытий; - Проще фильтровать инциденты по `req_id` и `session_id` в `docker compose logs api`. + +## 19) Обновления (2026-04-23, лимиты + нагрузка) + +1. Исправление гонки лимитов активных сервисов: +- Зафиксирован кейс, когда при параллельных открытиях сервисов одним пользователем лимит мог временно обходиться (наблюдалось до 8 активных сервисов). +- Причина: проверка лимита выполнялась вне критической секции. +- Исправление: в `go_service` добавлена пользовательская advisory-lock секция `allocator_lock(db, 92000 + user.id)`, внутри которой выполняются: + - проверка существующей сессии по сервису, + - проверка/ротация по лимиту, + - создание новой сессии. +- Результат: операции открытия сервисов для одного пользователя сериализованы, лимит применяется стабильно. + +2. Нагрузочное тестирование (k6): +- Добавлен скрипт `scripts/load/portal_k6.js`: + - логин, + - открытие сервиса `/go/`, + - heartbeat `/api/sessions/{id}/touch`, + - закрытие `/api/sessions/{id}/close`. +- Добавлены профили: `smoke`, `load`, `stress`. +- Добавлены пользовательские метрики: `open_success`, `open_rejected`, `limit_redirects`, `touch_rejected`, `flow_errors`. +- Добавлена инструкция запуска: `docs/LOAD_TESTING.md`. + +3. Git фиксация: +- Commit: `1438dee` +- Message: `feat: improve session limit handling and add k6 load testing` + +## 16) Обновления (2026-04-24, вынос maintenance в отдельный контейнер) + +1. Выделен отдельный сервис maintenance: +- Добавлен контейнер `maintenance` в `docker-compose.yml`. +- Команда контейнера: `python maintenance_runner.py`. +- Назначение: единственный фоновый процесс обслуживания пулов и cleanup просроченных сессий. + +2. Поведение API на старте изменено: +- Для `api` установлен флаг `ENABLE_STARTUP_MAINTENANCE=0`. +- API-воркеры больше не запускают maintenance-потоки при startup. +- В логах API при старте ожидаемое сообщение: `startup_maintenance_disabled`. + +3. Что делает maintenance-контейнер: +- bootstrap схемы БД (под schema-lock), +- `ensure_universal_pool()` и `ensure_web_pool()`, +- поддержка warm-pool (когда WEB pool отключен), +- cleanup протухших сессий (через существующий `cleanup_loop`). + +4. Блокировка лидера maintenance: +- Используется file-lock `/tmp/portal-maintenance.lock`. +- Контейнер maintenance удерживает lock и работает как singleton. + +5. Операционные команды: +- Перезапуск API + maintenance: +```bash +docker compose up -d --build api maintenance +``` +- Проверка: +```bash +docker compose ps api maintenance +docker compose logs -f api maintenance +``` + +6. Текущее целевое состояние после обновления: +- `api` отвечает за пользовательские HTTP-запросы. +- `maintenance` отвечает за фоновые задачи и состояние пулов. +- Traefik продолжает маршрутизацию как и раньше. + +## 17) Нагрузочный прогон (2026-04-24, 100 пользователей x 2 сервиса) + +Сценарий: +- 100 тестовых пользователей `loadu001..loadu100` (пароль `LoadTest!2026`), +- каждому выдан доступ к 2 WEB-сервисам: `termidesk`, `vmmanager`, +- тест: каждый пользователь логинится и запускает оба сервиса последовательно. + +Инструмент и артефакты: +- k6 через Docker: `grafana/k6`, +- скрипт: `/root/Stend_mont/scripts/load/k6_100_users_2_services.js`, +- вывод прогона: `/tmp/k6_100x2.out`. + +Итог прогона: +- `iterations`: 100 (по одной на VU), +- `checks_succeeded`: 41.61% (124/298), +- `http_req_failed`: 41.13% (174/423), +- `open termidesk -> 303`: 14% (14/99), +- `open vmmanager -> 303`: 11% (11/99), +- p95 `http_req_duration`: ~9.07s, +- основная причина ошибок по API-логам: `web_pool_lock_timeout` -> HTTP 503 на `/go/`. + +Вывод: +- при burst-нагрузке 100x2 текущий WEB-пул и таймауты распределения не выдерживают, +- требуется увеличение емкости/параметров пула и повторный прогон. + +## 18) Нагрузочный прогон (2026-04-24, плавный 20 пользователей x 2 сервиса) + +Цель: +- проверить поведение без резкого пика; +- имитировать постепенное подключение: +1 пользователь в минуту; +- довести до 20 online, каждый запускает 2 WEB-сервиса (termidesk, vmmanager). + +Подготовка: +- временно увеличен idle timeout для теста: + - .env: SESSION_IDLE_SECONDS=7200; + - WEB runtime слоты пересозданы, чтобы получили IDLE_TIMEOUT=7200. +- API и maintenance пересозданы с новыми env. + +Профиль нагрузки: +- k6 сценарий ramping-vus: + - 20m до 20 VU, + - 5m удержание 20 VU, + - 1m спад до 0. +- каждый VU: логин + /go/termidesk + /go/vmmanager, затем удержание. + +Фактический результат: +- k6 checks: 60/60 (100%); +- custom metrics: + - login_ok: 20/20; + - open_service_a_ok: 20/20; + - open_service_b_ok: 20/20; +- HTTP errors: 0/80; +- в БД после прогона: 40 ACTIVE WEB-сессий (20 termidesk + 20 vmmanager). + +Наблюдения по инфраструктуре: +- во время роста зафиксировано авторасширение WEB-пула до слотов 0..40; +- позже часть старших слотов была удалена, но в БД остались ACTIVE-сессии на слотах 20..39. + +Ресурсы сервера (по /tmp/server_stats_20x2.log): +- max load average (1m): 17.35; +- max used RAM: 9135 MB (из ~64 GB); +- max disk usage /: 96%; +- max CPU: + - stend_mont-api-1: 3.39%, + - stend_mont-traefik-1: 60.87%, + - stend_mont-db-1: 7.71%, + - single portal-webpool-*: до 250.44%. + +Вывод: +- плавный сценарий 20x2 проходит стабильно по HTTP/логике запуска; +- обнаружен риск целостности состояния: ACTIVE-сессии могут ссылаться на слоты, контейнеры которых уже scale-down/удалены.