Пошук уроків, статей та іншого контенту
Виконаєте швидкі оцінки запитів, даних, пропускної здатності та ресурсів за допомогою наближених розрахунків.
Back-of-the-envelope calculations — це швидкі наближені розрахунки, які допомагають оцінити масштаб системи ще до детального проєктування.
Вони потрібні, щоб відповісти на запитання:
скільки запитів система отримує за секунду;
яким буде пікове навантаження;
скільки даних накопичиться за день або рік;
якою буде пропускна здатність мережі;
скільки серверів, дискового простору або оперативної пам’яті потрібно;
чи є запропонована архітектура хоча б приблизно реалістичною.
Мета таких розрахунків — не отримати точне число до останнього байта. Мета — зрозуміти порядок величини: тисячі, мільйони чи мільярди запитів; гігабайти чи петабайти даних.
Для кожної оцінки:
Чітко сформулюйте, що саме рахуєте.
Запишіть припущення.
Переведіть добові значення в секунди або навпаки.
Розділіть навантаження на середнє та пікове.
Додайте запас для непередбачених ситуацій.
Перевірте одиниці вимірювання.
Округліть результат до зручного порядку величини.
Розрахунок без припущень неможливий. Наприклад, для оцінки навантаження потрібно знати:
кількість активних користувачів;
кількість дій одного користувача;
кількість HTTP-запитів на одну дію;
середній розмір запиту або відповіді;
співвідношення читань і записів;
коефіцієнт пікового навантаження;
термін зберігання даних;
кількість реплік.
Припущення не обов’язково будуть точними. Важливо явно їх назвати, щоб потім можна було змінити та перерахувати модель.
Для швидких оцінок зручно використовувати такі значення:
1 хвилина ≈ 60 секунд;
1 година ≈ 3 600 секунд;
1 доба ≈ 86 400 секунд;
1 місяць ≈ 30 днів;
1 рік ≈ 365 днів;
1 KB ≈ 1 000 байт;
1 MB ≈ 1 000 KB;
1 GB ≈ 1 000 MB;
1 TB ≈ 1 000 GB.
У системному дизайні часто важливіше зберегти однакову систему одиниць, ніж сперечатися про різницю між 1 000 і 1 024.
Зручні наближення:
1 мільйон запитів на добу — це приблизно 12 запитів за секунду;
10 мільйонів запитів на добу — приблизно 116 запитів за секунду;
100 мільйонів запитів на добу — приблизно 1 160 запитів за секунду.
Формула:
середня кількість запитів за секунду =
кількість запитів за добу / 86 400Припустімо, що маємо:
2,5 мільйона активних користувачів на день;
кожен користувач виконує 8 дій;
одна дія в середньому породжує 1 HTTP-запит.
Тоді:
запитів за добу = 2,5 млн × 8 = 20 млнСереднє навантаження:
20 млн / 86 400 ≈ 231 запит/сСереднє значення не показує реальний пік. Користувачі активні нерівномірно: вдень запитів більше, вночі — менше.
Якщо використати коефіцієнт піку 4:
пікове навантаження = 231 × 4 ≈ 924 запити/сУ практичному розрахунку можна округлити це до 1 000 запитів за секунду.
Система не повинна працювати на межі своїх можливостей. Додаємо, наприклад, 50% запасу:
цільова пропускна здатність =
1 000 × 1,5 = 1 500 запитів/сЦей запас потрібен для:
зростання кількості користувачів;
нерівномірних піків;
повторних запитів;
фонових операцій;
деградації окремих серверів;
тимчасового зростання навантаження.
Коефіцієнт піку та запас не є універсальними константами. Їх потрібно обирати відповідно до продукту та наявних метрик.
Загальну кількість запитів корисно розділити на читання і записи.
Нехай із 20 мільйонів запитів на добу:
97% — читання;
3% — записи.
Тоді:
читання за добу = 20 млн × 0,97 = 19,4 млн
записи за добу = 20 млн × 0,03 = 600 000Середня кількість записів за секунду:
600 000 / 86 400 ≈ 7 записів/сПікова кількість записів за секунду за коефіцієнта 4:
7 × 4 ≈ 28 записів/сЦе важливо для вибору сховища. Система може мати 1 000 запитів за секунду загалом, але лише 30 записів за секунду. Для бази даних це зовсім інший профіль навантаження, ніж 1 000 записів за секунду.
Нехай кожен запит повертає в середньому 35 KB даних.
Для 20 мільйонів запитів:
дані за добу = 20 млн × 35 KB
= 700 000 000 KB
≈ 700 GBЗа 30 днів:
700 GB × 30 = 21 000 GB ≈ 21 TBЦе логічний обсяг передбачених відповідей. Реальний обсяг зберігання може бути іншим, тому що:
частина відповідей генерується з даних, а не зберігається;
дані можуть стискатися;
у бази даних є індекси;
зберігаються журнали та метадані;
створюються резервні копії;
використовуються репліки.
Якщо потрібно мати три копії даних:
фізичний обсяг ≈ 21 TB × 3 = 63 TBДо цього варто додати запас. Наприклад, із 30% запасом:
63 TB × 1,3 ≈ 82 TBДля оцінки довготривалого зберігання часто важливіший розмір одного запису, ніж розмір HTTP-відповіді.
Нехай:
600 000 записів створюється на добу;
один запис займає 1,2 KB разом із необхідними полями.
Тоді:
дані за добу = 600 000 × 1,2 KB
= 720 000 KB
≈ 720 MBЗа рік:
720 MB × 365 ≈ 263 GBЯкщо врахувати індекси, метадані та дві додаткові репліки, фізичний обсяг буде приблизно:
263 GB × 3 ≈ 789 GBЦе все ще наближена оцінка. Індекси можуть збільшити обсяг значно сильніше або слабше залежно від структури даних.
Пропускна здатність залежить від кількості запитів та розміру даних.
Формула:
пропускна здатність =
запитів за секунду × розмір одного запиту або відповідіЗа пікового навантаження 1 000 запитів за секунду та відповіді розміром 35 KB:
1 000 × 35 KB = 35 000 KB/с ≈ 35 MB/сПереведемо в біти:
35 MB/с × 8 ≈ 280 Mbit/сЗ урахуванням запасу 50%:
280 Mbit/с × 1,5 = 420 Mbit/сПід час оцінки мережі потрібно уточнити, що саме рахується:
лише трафік від сервера до клієнта;
трафік у двох напрямках;
трафік між сервісами;
трафік між застосунком і базою даних;
трафік реплікації;
трафік резервного копіювання.
У розподіленій системі зовнішній трафік може бути невеликим, але внутрішній — значним через кілька міжсервісних викликів на один користувацький запит.
Припустімо, навантажувальний тест показав, що один сервер обробляє 150 запитів за секунду за прийнятної затримки.
Потрібна цільова пропускна здатність — 1 500 запитів за секунду.
кількість серверів = 1 500 / 150 = 10Отже, мінімальна оцінка — 10 серверів.
У реальній системі потрібно також врахувати:
резерв на відмову серверів;
нерівномірний розподіл запитів;
фонові задачі;
різні типи запитів;
обмеження бази даних;
пам’ять і CPU;
можливість горизонтального масштабування.
Якщо потрібно пережити відмову двох серверів, можна запустити 12 серверів. Тоді після втрати двох серверів залишиться 10 робочих серверів.
Важливо, що значення 150 запитів за секунду має походити з вимірювання або хоча б із консервативного припущення. Не можна надійно оцінити кількість серверів лише за кількістю ядер або частотою процесора.
Припустімо, що:
є 2,5 мільйона профілів;
у кеш потрібно помістити 10% найактивніших профілів;
один профіль займає 2 KB у серіалізованому вигляді.
кількість профілів у кеші = 2,5 млн × 0,1 = 250 000
сирий розмір = 250 000 × 2 KB = 500 000 KB ≈ 500 MBКеш зазвичай потребує додаткової пам’яті на:
ключі;
структури даних;
службові поля;
індекси;
фрагментацію;
реплікацію.
Якщо використати коефіцієнт 2:
необхідна пам’ять ≈ 500 MB × 2 = 1 GBЯкщо кеш має дві копії:
1 GB × 2 = 2 GBЦе не означає, що потрібно орендувати кеш рівно на 2 GB. На практиці потрібен додатковий запас, а граничний розмір залежить від політики витіснення даних.
Для приблизної оцінки кількості одночасних запитів можна використати співвідношення:
одночасні запити ≈ запитів за секунду × середня затримка в секундахНаприклад, за 1 000 запитів за секунду та середньої затримки 200 мс:
1 000 × 0,2 = 200 одночасних запитівЯкщо середня затримка зросте до 2 секунд:
1 000 × 2 = 2 000 одночасних запитівТому сервери, пули з'єднань і черги повинні бути розраховані не лише на RPS, а й на тривалість обробки запитів.
Це наближене застосування закону Літтла:
L = λ × Wде:
L — середня кількість елементів у системі;
λ — швидкість надходження елементів;
W — середній час перебування елемента в системі.
Нижче наведено невеликий самодостатній скрипт для оцінки запитів, трафіку, записів, сховища та кількості серверів.
const usersPerDay = 2_500_000;
const actionsPerUser = 8;
const requestsPerAction = 1;
const peakFactor = 4;
const capacityHeadroom = 1.5;
const responseSizeKB = 35;
const writeRatio = 0.03;
const recordSizeKB = 1.2;
const retentionDays = 30;
const replicationFactor = 3;
const requestsPerServer = 150;
const secondsPerDay = 86_400;
const kbPerGb = 1_000_000;
const kbPerTb = 1_000_000_000;
const requestsPerDay =
usersPerDay * actionsPerUser * requestsPerAction;
const averageRps = requestsPerDay / secondsPerDay;
const peakRps = averageRps * peakFactor;
const targetRps = peakRps * capacityHeadroom;
const averageBandwidthMBps =
(peakRps * responseSizeKB) / 1_000;
const averageBandwidthMbps = averageBandwidthMBps * 8;
const writesPerDay = requestsPerDay * writeRatio;
const averageWritesPerSecond = writesPerDay / secondsPerDay;
const peakWritesPerSecond = averageWritesPerSecond * peakFactor;
const responseDataPerDayKB = requestsPerDay * responseSizeKB;
const responseDataPerDayGB = responseDataPerDayKB / kbPerGb;
const recordsDataPerDayKB = writesPerDay * recordSizeKB;
const logicalStorageGB =
(recordsDataPerDayKB * retentionDays) / kbPerGb;
const physicalStorageTB =
(logicalStorageGB * replicationFactor) / 1_000;
const requiredServers = Math.ceil(targetRps / requestsPerServer);
console.log({
requestsPerDay: Math.round(requestsPerDay),
averageRps: Number(averageRps.toFixed(1)),
peakRps: Math.round(peakRps),
targetRps: Math.round(targetRps),
averageBandwidthMBps: Number(averageBandwidthMBps.toFixed(1)),
averageBandwidthMbps: Math.round(averageBandwidthMbps),
writesPerDay: Math.round(writesPerDay),
averageWritesPerSecond: Number(averageWritesPerSecond.toFixed(1)),
peakWritesPerSecond: Math.round(peakWritesPerSecond),
responseDataPerDayGB: Math.round(responseDataPerDayGB),
logicalStorageGB: Math.round(logicalStorageGB),
physicalStorageTB: Number(physicalStorageTB.toFixed(2)),
requiredServers
});Цей скрипт не замінює навантажувальні тести. Його призначення — швидко перевірити припущення та побачити, як зміна одного параметра впливає на масштаб системи.
Наприклад, збільшення actionsPerUser удвічі приблизно подвоїть:
кількість запитів;
мережевий трафік;
навантаження на сервери;
кількість записів, якщо співвідношення записів не зміниться.
Після розрахунку поставте собі кілька запитань:
Чи правильно переведено добове навантаження в секунди?
Чи враховано пікове навантаження?
Чи відділено читання від записів?
Чи однакові одиниці вимірювання в усіх формулах?
Чи не переплутано KB із Kbit?
Чи враховано реплікацію?
Чи враховано індекси та службові дані?
Чи має сервер гарантовану пропускну здатність, підтверджену тестом?
Чи залишився запас після відмови частини інфраструктури?
Чи не є середні значення небезпечно оптимістичними?
Корисно виконати розрахунок у трьох сценаріях:
оптимістичному;
базовому;
песимістичному.
Наприклад, можна змінити кількість користувачів, коефіцієнт піку або розмір відповіді й перевірити, чи не змінюється порядок величини результату.
Середнє значення приховує піки. Система, яка витримує 250 запитів за секунду в середньому, може потребувати потужності для 1 000 запитів за секунду.
Число «потрібно 10 серверів» нічого не пояснює без інформації про:
кількість запитів;
тип запитів;
розмір відповідей;
продуктивність одного сервера;
запас потужності.
Розмір файлу зазвичай вказують у байтах, а мережеву швидкість — у бітах за секунду.
1 байт = 8 бітТому 100 MB/с — це приблизно 800 Mbit/с.
Логічний обсяг записів не дорівнює фізичному обсягу на дисках. Репліки, індекси, журнали й резервні копії можуть збільшити потребу в сховищі в кілька разів.
Результат 926,37 запиту/с створює хибне відчуття точності. Якщо початкові дані приблизні, корисніше сказати «приблизно 1 000 запитів за секунду».
Продуктивність залежить від конкретного типу операції. Сервер може обробляти тисячі простих операцій читання, але лише десятки складних операцій із записом і транзакціями.
Потрібно чітко розділяти:
коефіцієнт пікового навантаження;
запас для зростання;
резерв на відмову серверів.
Інакше запас можна випадково застосувати двічі або не застосувати взагалі.
Back-of-the-envelope calculations допомагають швидко оцінити масштаб системи.
Починайте з явних припущень і не намагайтеся отримати псевдоточний результат.
Для RPS переводьте добову кількість запитів через 86 400 секунд.
Окремо оцінюйте середнє, пікове та цільове навантаження із запасом.
Розділяйте читання і записи, оскільки вони по-різному впливають на інфраструктуру.
Для трафіку множте кількість запитів за секунду на розмір запиту або відповіді.
Для сховища враховуйте термін зберігання, реплікацію, індекси та службові дані.
Кількість серверів оцінюйте на основі виміряної продуктивності одного сервера.
Пам’ятайте про зв’язок між RPS, затримкою та кількістю одночасних запитів.
Після приблизних оцінок результати потрібно перевірити навантажувальним тестуванням і реальними метриками.