packmate/docs/CLEANUP.md

12 KiB
Raw Blame History

Очистка старых потоков

В режиме LIVE Packmate периодически удаляет старые потоки, кроме отмеченных как favorite. Удаление выполняется короткими независимыми транзакциями напрямую в PostgreSQL и не загружает граф Stream -> Packet -> FoundPattern в Hibernate.

По умолчанию очистка включена в Docker Compose и сохраняет последние 15 минут:

Переменная Значение Назначение
PACKMATE_OLD_STREAMS_CLEANUP_ENABLED true Включает задачу
PACKMATE_OLD_STREAMS_CLEANUP_THRESHOLD 15 Retention для non-favorite потоков в минутах
PACKMATE_OLD_STREAMS_CLEANUP_INTERVAL_SECONDS 10 Пауза между запусками в секундах
PACKMATE_OLD_STREAMS_CLEANUP_MAX_RUN_SECONDS 5 После этого cleaner не начинает новые пачки
PACKMATE_OLD_STREAMS_CLEANUP_COMMIT_GRACE_SECONDS 120 Минимальное время после записи до очистки
PACKMATE_OLD_STREAMS_CLEANUP_BATCH_SIZE 500 Максимум потоков в транзакции
PACKMATE_OLD_STREAMS_CLEANUP_MAX_BATCHES_PER_RUN 20 Максимум транзакций за один запуск
PACKMATE_OLD_STREAMS_CLEANUP_MAX_PACKETS_PER_BATCH 20000 Бюджет пакетов на транзакцию
PACKMATE_OLD_STREAMS_CLEANUP_MAX_MATCHES_PER_BATCH 20000 Бюджет найденных совпадений на транзакцию
PACKMATE_OLD_STREAMS_CLEANUP_MAX_BYTES_PER_BATCH 67108864 Бюджет содержимого на транзакцию
PACKMATE_OLD_STREAMS_CLEANUP_STATEMENT_TIMEOUT_SECONDS 5 Общий deadline одной cleanup-транзакции
PACKMATE_OLD_STREAMS_CLEANUP_LOCK_TIMEOUT_SECONDS 1 Лимит ожидания блокировки

PostgreSQL запускается с более частым autovacuum. Параметры заданы также в docker-compose.yml, поэтому применяются к уже существующему volume после перезапуска контейнера БД.

Перед удалением поток помечается как находящийся в очистке и перестаёт попадать в выдачу и lookback. Пакеты удаляются ограниченными кусками. Если приложение или БД перезапустятся посередине, следующий запуск продолжит такой поток. Поэтому один большой TCP stream не блокирует всю очередь очистки.

Retention и частота полностью настраиваются через .env. Например, чтобы хранить час истории и запускать cleaner каждые 30 секунд:

PACKMATE_OLD_STREAMS_CLEANUP_THRESHOLD=60
PACKMATE_OLD_STREAMS_CLEANUP_INTERVAL_SECONDS=30

В старых конфигурациях интервал задавался в минутах через PACKMATE_OLD_STREAMS_CLEANUP_INTERVAL. Теперь используется PACKMATE_OLD_STREAMS_CLEANUP_INTERVAL_SECONDS; старую переменную нужно заменить. MAX_RUN_SECONDS ограничивает момент запуска следующей пачки. Внутри пачки оставшееся время SQL пересчитывается перед каждым запросом, поэтому вся транзакция ограничена STATEMENT_TIMEOUT_SECONDS.

Для соревнований effective cleanup throughput должен быть выше скорости, с которой трафик пересекает retention cutoff. Если Packmate начинает деградировать через 25–30 минут, безопасный исходный retention — 15 минут; favorite потоки не удаляются.

Стресс тест

Тест всегда создаёт одноразовый PostgreSQL через Testcontainers. Рабочая база Packmate не используется.

./gradlew stressTest

Стандартный профиль создаёт 30 000 обычных потоков, oversized поток с ложной метаинформацией и более 900 000 пакетов. Он использует production лимиты запусков и паузы, параллельно запускает два writer и проверяет:

  • удаление всех старых non-favorite данных и сохранение favorite/new данных;
  • отсутствие потерянных новых записей и orphan rows;
  • возобновление oversized потока несколькими ограниченными транзакциями;
  • p99 задержки ingest не выше 500 мс;
  • длительность одной cleanup пачки не выше 5 секунд;
  • скорость очистки не ниже 5 000 пакетов/с;
  • запуск autovacuum и снижение dead tuples до 50 000.

Отчёт сохраняется в build/reports/cleanup-stress.json. Размер нагрузки и пороги настраиваются переменными PACKMATE_STRESS_*, перечисленными в OldStreamsCleanerStressTest.

Сетевой end-to-end stress test

OldStreamsCleanerStressTest изолирует производительность PostgreSQL. Отдельный Linux/Docker стенд проверяет весь production тракт: реальные TCP соединения через Docker veth, захват libpcap, сборку потоков, очередь обработчика, Hibernate, PostgreSQL, cleaner и REST API.

sh stress/network/run.sh

По умолчанию тест создаёт 250 000 исходных TCP соединений и ещё 50 000 соединений во время очистки. В каждом соединении передаётся восемь пар request/response с payload 1024 байта. Нагрузка распределяется между 16 контейнерами с отдельными source IP, чтобы один диапазон ephemeral ports не ограничивал результат. Это около 4,8 млн прикладных сообщений плюс TCP handshake, ACK и FIN.

Перед очисткой тест полностью выгружает ledger сохранённых потоков и для каждого независимо проверяет run_id, connection ID, shard, полную длину и MD5 payload в обоих направлениях, а также IP адреса. Дополнительно 200 потоков проверяются через REST API. После этого тест искусственно сдвигает timestamp уже захваченных строк за retention cutoff, чтобы проверить production cleaner без ожидания полного retention period, и одновременно продолжает подавать свежий сетевой трафик. Тестовый retention по умолчанию равен 1440 минутам, поэтому случайно свежие строки не попадают в cleanup. Live фаза длится не менее 20 секунд и PASS возможен только при измеренном пересечении commit новых потоков с удалением baseline.

Тест завершается ошибкой при любой ошибке генератора, потере сохранённого потока, повреждении проверяемого payload, pcap drop, capture queue более 500 000 пакетов, orphan row, незавершённом cleanup или REST p99 выше 500 мс. После baseline проверяется ранний gate, поэтому заведомо повреждённый прогон не маскирует потери длительным ожиданием ingest. Размер capture queue измеряется монотонным high water mark внутри приложения. При превышении лимита monitor создаёт общий abort marker, и все генераторы перестают открывать новые соединения. Cleaner должен удалять не менее 500 streams/s; порог настраивается. PostgreSQL создаётся в отдельном Compose project на одноразовом Docker volume; до нагрузки проверяется доступное место. Рабочая база Packmate не используется. JSON отчёты, effective config, overlap timeline и логи сохраняются в отдельном каталоге запуска под build/reports/network-stress/.

Контрольный запуск 23 октября 2026 года показал предел старого однопоточного capture path: при 250 000 TCP соединений libpcap сообщил 1 967 297 drops, а неограниченная очередь выросла до 4 894 878 задач. После перехода на 12 flow-sharded workers повторный baseline сохранил 250 000 из 250 000 соединений и 8 013 904 захваченных пакета без kernel, interface или application drops. Полный ledger подтвердил payload и метаданные всех 250 000 потоков; очередь полностью опустела, её high water составил 61 396 из 500 004 задач. Следующая волна передала ещё 50 000 соединений во время cleanup без ошибок генератора и packet drops; её high water составил 120 570.

Отдельный завершённый профиль 5 000 + 1 000 прошёл весь ingest/cleanup/ledger цикл, включая измеренное пересечение cleaner с live traffic, сохранение favorite, REST p99 189,686 мс и отсутствие orphan rows. Production по умолчанию сохраняет PACKMATE_CAPTURE_WORKERS=1 как безопасный режим совместимости; число workers нужно выбирать по результатам этого стенда на реальном сервере. Throughput генераторов измеряется от старта первого до завершения последнего workload-процесса и не включает создание Docker контейнеров.

Для длительного прогона на миллион соединений:

PACKMATE_NETWORK_STRESS_STREAMS=1000000 \
PACKMATE_NETWORK_STRESS_LIVE_STREAMS=100000 \
PACKMATE_NETWORK_STRESS_SHARDS=16 \
sh stress/network/run.sh

Основные параметры: PACKMATE_NETWORK_STRESS_STREAMS, PACKMATE_NETWORK_STRESS_LIVE_STREAMS, PACKMATE_NETWORK_STRESS_SHARDS, PACKMATE_NETWORK_STRESS_CONCURRENCY, PACKMATE_NETWORK_STRESS_FRAMES_PER_STREAM, PACKMATE_NETWORK_STRESS_PAYLOAD_BYTES, PACKMATE_NETWORK_STRESS_MAX_CAPTURE_QUEUE, PACKMATE_NETWORK_STRESS_MIN_LIVE_DURATION_SECONDS, PACKMATE_NETWORK_STRESS_MIN_CLEANUP_STREAMS_PER_SECOND и таймауты PACKMATE_NETWORK_STRESS_*_TIMEOUT_SECONDS. PACKMATE_NETWORK_STRESS_RUN_ID задаёт имя каталога отчёта. В GitLab CI малый профиль network-smoke обязателен, а дорогой capacity профиль доступен как ручной job network-stress; отчёты обоих сохраняются как artifacts.