Нагрузочный тест Orbitra: 480 запросов/с, ноль ошибок, p99 182 мс
Трекер живёт под нагрузкой: каждый клик — это запись, проверка уникальности и редирект. Поэтому перед тегом v1.6.3 мы перестроили конвейер уникальности на базе боевого масштаба и прогнали её ступенчатой нагрузкой k6 на тестовом стенде. Вот цифры.
Зачем мы это прогнали
v1.6.3 сделала фильтр дублей честным к мобильному NAT: ключ уникальности стал IP + user agent вместо голого IP. За одним NAT-IP оператора раньше сталкивались два разных человека — второй получал subid без строки клика в базе, и его конверсии было не к чему привязать.
Изменение потребовало новую колонку ua_hash и составной индекс на базе, которая уже несёт реальный объём. Это самый страшный тип миграции — поэтому перед тегом мы воспроизвели ровно тот путь, который проходит установка пользователя, на данных боевого масштаба.
Стенд
- Облачный контейнер: 2 vCPU / 7 ГБ RAM, Ubuntu 24.04. nginx 1.24 + PHP-FPM 8.3 в стоковой конфигурации — ровно такой, какой её оставляет
install.sh, без ручной подкрутки в базовых прогонах. - SQLite в режиме WAL. k6 работает на той же машине (~0,3 ядра накладных), так что цифры скорее занижены.
- Ступенчатая нагрузка constant-arrival-rate: 60 секунд на ступень, таймаут 5 с, редиректы не следуются.
- Кампания: один обычный поток → редирект на оффер, окно уникальности 24 часа по IP + User-Agent. Уники — случайный публичный IP и уникальный UA; повторные — 50 фиксированных пар IP/UA.
- Три базы: ~50 тыс. кликов (санити), 3,2 млн (основная) и снимок до обновления на 3,9 млн для репетиции миграции (~1 млн — за последние сутки, ~8 500 кликов на NAT-IP).
- Прогоны парами: v1.6.2 работала на той же базе рядом с новой версией; после упавшего прогона ждали, пока рассосётся очередь FPM.
Результаты
| Прогон (база 3,2 млн, если не сказано) | rps | Ошибки | p99 | CPU |
|---|---|---|---|---|
| Уники, стоковый FPM (база ~50 тыс.) | 480 | 0 | 46 мс | 76% |
| Уники | 480 | 0 | 75 мс | 77% |
| Повторные посетители (50 NAT-пар) | 480 | 0, ~1% через spool | 14 мс | 61% |
| Уники + открытая панель, отчёты обновляются каждые 2 с | 320 | 0 | 587 мс | 81% |
| Уники, тюнинг FPM/nginx, гео-база включена | 560 | 0 | 187 мс | 94% |
| Уники, намеренная перегрузка | 800 | 27% таймаутов | — | 97% |
И репетиция миграции на снимке в 3,9 млн кликов: первый запрос после «обновления» выполнил миграцию 55 за 0,04 с, один проход крона собрал индекс за 4,8 с и досчитал 1 008 085 UA-хэшей за 29,6 с — а NAT-трафик на 480 запросов/с прошёл с нулём ошибок и p99 182 мс, все subid в базе. Прошлая версия в том же сценарии теряла 27 775 subid, новая — ноль.
Две детали напоследок. Даже на 800 запросах/с — за точкой излома — каждый отработанный редирект всё равно записан в базу: перегрузка ухудшает задержку, но не долговечность. И корректность хэшей: выборка в 2 000 строк сверена с PHP crc32 — ни одного расхождения.
Экономика: один клик стоит около 2,5 мс CPU — это потолок ~550–600 запросов/с для 2 vCPU, упор в процессор. На 4 vCPU та же арифметика даёт ~1 000 запросов/с — но это экстраполяция на бумаге, и мы её так и подписываем.
Что стресс-тест поймал до релиза
Половина ценности прогона — баги, которые он выловил. Все закрыты до тега:
- Незакрытые курсоры на пути клика давали мгновенный SQLITE_BUSY_SNAPSHOT — клики повторных посетителей уходили в spool вместо базы.
- Дебаунс ключился только по IP — соседи по NAT теряли клики и получали несуществующий subid.
- Фильтры дат в отчётах использовали date(created_at, tz) и не попадали в индекс — отчёты ползли на больших базах.
- В пиксельном INSERT было 23 колонки и 22 значения — пиксельные клики молча терялись.
- Старые строки с NULL-хэшем держали NAT-коллапс живым одно окно уникальности после обновления.
Почему это работает
- SQLite в режиме WAL, один файл, ноль лишних сервисов. Нет ClickHouse, Redis и MySQL, которые съедают RAM, — узкое место это дисковый I/O, и он масштабируется вместе с VPS.
- Очередь записи (spool): если SQLite на мгновение заблокирована, клик уходит в файловую очередь, и поминутный крон её досылает — редирект посетителя не ждёт, клик не теряется.
- Проверки уникальности идут по индексу: клик несёт компактный crc32-хэш UA, и четыре проверки на клик ищут по индексу (ip, ua_hash, created_at), а не перебирают все клики IP.
Честные оговорки
- Тест — на релиз-кандидате v1.6.3. Архитектура хранения (SQLite, spool, индексы) в текущих версиях не менялась.
- Наш стенд — не ваш VPS: абсолютные цифры переезжают вместе с железом. Переносятся соотношения и характер отказа.
- Цифра для 4 vCPU — экстраполяция, не замер; мы говорим так, а не округляем вверх.
- Это синтетический стресс-прогон плюс репетиция миграции на боевом масштабе, а не A/B на реальном трафике против других трекеров.
Что это значит для вас
Скромный VPS того класса, который большинство гайдов советуют для старта, уже имеет запас под серьёзные дневные объёмы — и над ним не ждёт тарифная сетка за события. Если вы сидите на Keitaro из-за «SQLite не выживет», вот датасет, на который стоит посмотреть.
Orbitra ставится на чистый Ubuntu-сервер примерно за 15 минут — одна команда, а живое демо открыто, если хотите сначала потыкать панель.
FAQ
На каком железе гоняли тест?
На облачном контейнере с 2 vCPU и 7 ГБ RAM под Ubuntu 24.04, nginx и PHP-FPM в стоковой конфигурации от install.sh, а k6 — на той же машине, так что цифры скорее занижены. Абсолютные значения всегда зависят от вашего VPS: вы масштабируете сервер, а не тариф.
Эти результаты относятся к текущей версии?
Тест гоняли на релиз-кандидате v1.6.3. Архитектура хранения (SQLite + очередь записи + индексы уникальности) в текущих версиях та же; изменения после — фичи и интерфейс.
Почему SQLite, а не ClickHouse?
Один файл, режим WAL, никакого отдельного сервера БД. На малых и средних объёмах узкое место — дисковый I/O, а не RAM, поэтому дешёвый VPS уходит далеко. Для стабильно миллионов кликов в день колоночная архитектура сильнее — мы говорим об этом прямо.
Миграция не потеряла данные?
В сценарии повторных посетителей прошлая версия теряла 27 775 subid, новая — ноль. Отчёты по 3,2 млн кликов совпали с предыдущей версией строка в строку.
Читайте также
Альтернатива Voluum: бесплатный self-hosted трекер
Voluum — от ~$149/мес. Orbitra — бесплатный self-hosted трекер со встроенным клоакингом и 50+ интеграциями. Сравнение и гайд по миграции.
Читать статью →Альтернатива Keitaro: бесплатный self-hosted трекер
Ближайший self-hosted конкурент — но лицензия от $79/мес. Сравнение функций и перенос кампаний в один клик.
Читать статью →