Бенчмаркінг і порівняння продуктивності
Коротке резюме
Бенчмаркінг - це експеримент, а не «запустити wrk на 5 хвилин». Основні принципи:1. Сформулюйте гіпотезу і метрики.
2. Контролюйте змінні (залізо, ядро, живлення, шум фону).
3. Збирайте достатньо даних (репліки, довірчі інтервали).
4. Проводьте профілювання - без нього не зрозуміти «чому».
5. Робіть repro: скрипти, фіксація версій і артефактів.
Цілі бенчмарка і бізнес-метрики
Пропускна здатність (throughput): RPS/QPS/CPS, записи/сек.
Затримка (latency): р50/р95/р99/щільність хвостів.
Ефективність: Cost-per-1k RPS, ват на транзакцію, $/мілісекунду поліпшення.
Стабільність: джиттер, варіативність між циклами/нодами.
Еластичність: як масштабуються показники при N × ресурсу (Amdahl/Gustafson орієнтири).
Методологія: дизайн експерименту
Гіпотеза: «Envoy з HTTP/3 зменшить p95 TTFB на 10-15% при тому ж RPS».
Одиниця порівняння: версія білда/конфіг/інстанс заліза.
A/B-схема: паралельний прогін на ідентичному оточенні; або ABAB/Latin Square для зниження впливу дрейфу.
Кількість повторів: ≥ 10 коротких + 3 довгих прогону на конфігурацію для стійких оцінок.
Статистика: медіана, MAD, довірчі інтервали бутстрепом; непараметричні тести (Mann-Whitney) для «хвостатих» розподілів.
DoE (мінімально): змінюйте одну змінну за раз (OVAT) або фракційний факторний план для 2-3 факторів (наприклад, TLS-профіль × HTTP-версія × ядро).
Контроль змінних і шумів
CPU governor: `performance`; вимкнути «power save».
Turbo/Throttling: моніторинг частот, температур і троттлінгу (інакше прогрів дасть помилкові виграші).
NUMA/Hyper-Threading: закріплюйте IRQ і процеси ('taskset/numactl'), вимірюйте локальність пам'яті.
C-states/IRQ balance: фіксуйте налаштування; для мережевих тестів - pin IRQ на конкретні ядра.
Фонові процеси: чиста нода, вимкнути cron/backup/antivirus/updatedb.
Мережа: стабільні шляхи, фіксовані MTU/ECN/AQM, відсутність флаттера каналу.
Дані: однакові набори, кардиналітет і розподілу.
Кеш: поділяйте «холодний» (перший прохід) і «теплий» (повторний) режими, явно позначайте.
Класи бенчмарків
1) Мікро-бенчмарки (функція/алгоритм)
Мета: виміряти конкретний код/алгоритм.
Інструменти: вбудовані бенч-фреймворки (Go'testing. B`, JMH, pytest-benchmark).
Правила: прогрів JIT, мілісекунди → наносекунди; ізоляція GC; фіксований seed.
2) Мезо-бенчмарки (компонент/сервіс)
HTTP-сервер, кеш, брокер, БД на одній ноді.
Інструменти: wrk/wrk2, k6 (open model), vegeta, ghz (gRPC), fio, sysbench, iperf3.
Правила: ліміти з'єднань/файлів, пулів; звіт про CPU/IRQ/GC.
3) Макро-бенчмарки (е2е/шлях запиту)
Повний шлях: CDN/edge → proxy → сервіс → БД/кеш → відповідь.
Інструменти: k6/Locust/Gatling + RUM/OTel трейсинг; реалістична суміш маршрутів.
Правила: ближче до реальності («брудні» дані, лаги зовнішніх систем), акуратно з ретраями.
Набір метрик по шарах
Шаблони тестів і команди
Мережа (TCP/UDP):bash iperf3 -s # server iperf3 -c <host> -P 8 -t 60 # parallel, stable bandwidth
HTTP-сервер (стабільне навантаження, wrk2):
bash wrk2 -t8 -c512 -d5m -R 20000 https://api. example. com/endpoint \
--latency --timeout 2s
Open-модель (k6, arrival-rate):
javascript export const options = {
scenarios: { open: { executor: 'constant-arrival-rate', rate: 1000, timeUnit: '1s',
duration: '10m', preAllocatedVUs: 2000 } },
thresholds: { http_req_failed: ['rate<0. 3%'], http_req_duration: ['p(95)<250'] }
};
Диск (fio, 4k random read):
bash fio --name=randread --rw=randread --bs=4k --iodepth=64 --numjobs=4 \
--size=4G --runtime=120 --group_reporting --filename=/data/testfile
БД (sysbench + PostgreSQL приблизна ідея):
bash sysbench oltp_read_write --table-size=1000000 --threads=64 \
--pgsql-host=... --pgsql-user=... --pgsql-password=... prepare sysbench oltp_read_write --time=600 --threads=64 run
Пам'ять/CPU (Linux perf + stress-ng):
bash perf stat -e cycles,instructions,cache-misses,L1-dcache-load-misses \
-- <your_binary> --bench
Статистика і валідність
Повтори: мінімум 10 прогонів, виключити outliers (робастно: медіана/MAD).
Довірчі інтервали: бутстреп 95% CI для p95/p99 і середніх.
Ефект-розмір: відносна зміна і його CI (наприклад, −12% [−9%; −15%]).
Практична значимість: зменшення p95 на 10% при ціні + 30% CPU - чи варто?
Графіки: violin/ECDF для розподілів, «криві насичення» (RPS→latency).
Профілювання та локалізація вузького місця
CPU: `perf`, `async-profiler`, eBPF/pyroscope; flamegraph до і після.
Alloc/GC: профілі runtime (Go pprof/Java JFR).
I/O: `iostat`, `blktrace`, `fio --lat_percentiles=1`.
Мережа: `ss -s`, `ethtool -S`, `dropwatch`, `tc -s qdisc`.
БД: `EXPLAIN (ANALYZE, BUFFERS)`, pg_stat_statements, slowlog.
Кеш: топ-ключі, TTL, eviction причина.
Звітність та артефакти
Що фіксувати:- git SHA білда, прапори компіляції/оптимізації.
- Конфіги ядра/мережі (sysctl), версії драйверів/NIC/firmware.
- Топологію (vCPU/NUMA/HT), governor, температура/частоти.
- Дані: розмір, кардиналітет, розподілу.
- Що публікувати: таблиці p50/p95/p99, помилка/сек, throughput, ресурси (CPU/RAM/IO), CI.
- Артефакти: скрипти прогону, графіки, flamegraph, сирий JSON/CSV результатів, протокол оточення.
Чесні порівняння (fair benchmarking)
Ідентичні обмежувачі (conn pool, keepalive, TLS ланцюжка, OCSP stapling).
Узгоджені таймаути/ретраї і HTTP версія (h2/h3).
Температурний баланс: прогрів до рівноваги (без turbo-буст ефекту).
Справедливі кеші: або обидва «холодні», або обидва «теплі».
Мережева симетрія: однакові маршрути/MTU/ECN/AQM.
Бюджет часу: DNS/TLS/connect - вважати явно або виключати однаково.
Анти-патерни
Один прогін → «висновок».
Змішування режимів (частина холодних, частина теплих) в одній серії.
Закрита модель замість відкритої для інтернет-навантаження → помилкова «стійкість».
Невраховані ретраї → «RPS зростає» ціною дублів і каскадних 5xx.
Порівняння на різних залозках/ядрах/енергосхемах.
Відсутність профілювання → оптимізація «наосліп».
Гра з GC/heap без аналізу профілів → регресії хвостів.
Практичні рецепти
Кроки мінімального бенч-пайплайну:1. Зафіксувати оточення (скрипт'env _ capture. sh`).
2. Прогріти (5-10 хв), зафіксувати частоти/температури.
3. Провести N повторів коротких + 1 довгий прогін.
4. Зняти профілі (CPU/alloc/IO) на піку.
5. Порахувати CI/графіки, зібрати артефакти.
6. Рішення: прийняти/відхилити гіпотезу, сформувати next steps.
Крива ємності (capacity curve):- Ступені RPS (10% кроку) → фіксуємо р95/помилки → знаходимо «коліно».
- Будуємо графік RPS→latency і RPS→CPU: бачимо кордон і вартість подальших%.
Специфіка для iGaming/фінтех
Вартість мілісекунди: ранжируйте поліпшення по $ -ефекту (конверсія/відтік/ліміти PSP).
Піки (матчі/турніри): бенчмарки spike + plateau з прогрівом TLS/CDN/кешів.
Платежі/PSP: вимірюйте end-to-end з sandbox-лімітами, ідемпотентність і реакції на деградації; фіксуйте Time-to-Wallet проксі-метриками.
Антифрод/бот-фільтри: включайте в макро-бенч профіль правил (false-positive-rate, latency добавка).
Лідери/джекпоти: тестуйте гарячі ключі/ранжування, блокування, атомарність.
Чек-лист бенчмаркінгу
- Гіпотеза/метрики/критерій успіху.
- Контроль змінних (живлення/NUMA/IRQ/мережа/кеш).
- План прогонів (репліки, тривалість, прогрів).
- Розділення «холод/теплий» режимів.
- Профілювання включено (CPU/alloc/IO/БД).
- Статистика: CI, тести значущості, графіки.
- Артефакти і repro-скрипти в репозиторії (IaC для стенду).
- Звіт з «вартістю поліпшення» і рекомендаціями.
- Ретест після оптимізацій (regression perf).
Міні-звіт (шаблон)
Мета: зменшити p95 API на 15% без зростання CPU> 10%.
Метод: A/B, k6 open-model 1k rps, 10 × 3 прогону, warm cache.
Разом: p95 −12% [−9%; −15%], CPU + 6%, 5xx без змін.
Flamegraph: ↓ JSON серіалізація (−30% CPU), вузьке місце змістилося в БД.
Рішення: прийняти оптимізацію; наступний крок - батчування запитів БД.
Артефакти: графіки, профілі, конфіги, сирий JSON.
Підсумок
Хороший бенчмаркінг - це сувора методологія + чесні порівняння + статистична валідність + профілювання + відтворюваність. Ставте гіпотези, контролюйте оточення, вважайте довірчі інтервали, публікуйте артефакти і приймайте рішення щодо вартості поліпшення. Так ви отримаєте не красиву цифру в презентації, а реальний приріст швидкості і передбачуваності платформи.