Навантажувальний тест 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/міс. Порівняння функцій та перенос кампаній в один клік.
Читати статтю →