Пошук уроків, статей та іншого контенту
Розберете затримку, пропускну здатність і доступність, а також навчитеся знаходити компроміси між цими характеристиками.
Під час проєктування системи важливо розуміти не лише, чи працює вона функціонально. Потрібно також оцінювати:
latency — скільки часу займає обробка одного запиту;
throughput — скільки запитів або операцій система обробляє за одиницю часу;
availability — яку частину часу система доступна для користувачів.
Ці характеристики пов’язані, але не є взаємозамінними. Система може мати високу пропускну здатність, але повільно відповідати на окремі запити. Або відповідати дуже швидко, але часто бути недоступною.
Latency — це час від моменту надсилання запиту до моменту отримання відповіді.
Наприклад, якщо API отримало запит о 12:00:00.000, а відповідь надійшла о 12:00:00.120, затримка становить 120 мс.
На latency можуть впливати:
мережевий обмін між клієнтом і сервером;
час виконання коду;
звернення до бази даних;
очікування в черзі;
виклики інших сервісів;
серіалізація та передавання великих відповідей;
блокування ресурсів.
Середня latency може приховувати повільні запити. Наприклад, для десяти запитів із часом відповіді:
10, 12, 11, 10, 13, 12, 11, 10, 500, 11 мсСереднє значення буде близько 59 мс, хоча більшість запитів виконується приблизно за 10–13 мс.
Тому часто використовують перцентилі:
p50 — медіанна затримка: половина запитів швидша, половина повільніша;
p95 — 95% запитів завершуються не повільніше за це значення;
p99 — 99% запитів завершуються не повільніше за це значення.
Для користувацьких систем p95 і p99 часто корисніші за середнє значення, тому що показують поведінку повільного «хвоста» запитів.
Якщо p99 дорівнює
2 с, це означає, що приблизно один запит зі ста може тривати дві секунди або довше.
Latency може складатися з кількох частин:
latency =
час передавання запиту
+ час очікування в черзі
+ час обробки
+ час передавання відповідіНавіть якщо обробка запиту займає лише 20 мс, користувач може отримати відповідь через 300 мс, якщо запит довго чекає в черзі.
Саме тому збільшення кількості паралельних запитів не завжди покращує систему. Коли ресурси насичуються, зростає черга, а разом із нею — latency.
Throughput — кількість роботи, яку система виконує за одиницю часу.
Приклади одиниць вимірювання:
запити за секунду — requests per second, або RPS;
транзакції за секунду — TPS;
повідомлення за секунду;
мегабайти за секунду.
Формула для запитів:
throughput = кількість запитів / тривалість вимірювання
Якщо за 10 секунд система обробила 5000 запитів, її середня пропускна здатність становить:
5000 / 10 = 500 RPSВарто розрізняти:
максимальний throughput — найбільше навантаження, яке система може витримати протягом короткого часу;
стабільний throughput — навантаження, за якого система тривалий час працює без неконтрольованого зростання черг, помилок і latency.
Наприклад, сервіс може короткочасно обробляти 2000 RPS, але стабільно працювати лише на 1200 RPS. Після перевищення цього рівня черги збільшуються, p95 latency погіршується, а згодом з’являються тайм-аути.
Розглянемо два сервіси:
сервіс A обробляє один запит за 10 мс;
сервіс B обробляє один запит за 100 мс, але має 100 паралельних робочих процесів.
Сервіс B може мати вищий throughput, хоча окремий запит у ньому повільніший.
Тому під час оцінювання системи потрібно одночасно дивитися на:
latency окремих запитів;
throughput під заданим навантаженням;
використання CPU, пам’яті, мережі та інших ресурсів;
кількість помилок і тайм-аутів.
Для приблизного аналізу корисний закон Літтла:
кількість запитів у системі = throughput × середній час перебування в системі
Або:
L = λ × W
де:
L — середня кількість запитів у системі;
λ — throughput;
W — середня latency.
Наприклад, якщо система обробляє 100 RPS, а середній запит триває 0,2 с, то в системі в середньому перебуває:
100 × 0,2 = 20 запитівЦе не означає, що закон Літтла сам по собі визначає продуктивність. Він допомагає побачити наслідки змін:
якщо throughput залишається сталим, а latency зростає, збільшується кількість запитів, що одночасно перебувають у системі;
якщо додати паралельні ресурси, можна збільшити throughput, але після насичення вузького місця latency почне швидко зростати.
Availability — частка часу, протягом якого система доступна та виконує свою функцію відповідно до визначених критеріїв.
Базова формула:
availability = час доступності / загальний час × 100%
Якщо за місяць система була недоступна 30 хвилин, а в місяці 43 200 хвилин:
availability = (43 200 - 30) / 43 200 × 100%
≈ 99,93%Доступність часто описують «дев’ятками»:
99% — приблизно 7 годин 18 хвилин недоступності на місяць;
99,9% — приблизно 43 хвилини 12 секунд;
99,99% — приблизно 4 хвилини 19 секунд;
99,999% — приблизно 26 секунд.
Ці значення є орієнтовними для 30-денного місяця.
Система може бути формально доступною, але практично непридатною:
API відповідає 200 OK, але робить це за 30 секунд;
сторінка відкривається, але повертає застарілі або неправильні дані;
доступний лише один із важливих функціональних компонентів;
відповіді з помилками вважаються «відповідями», хоча операція не виконана.
Тому критерії доступності потрібно визначати разом із поведінкою сервісу. Наприклад:
запит вважається успішним лише за статусом 2xx;
latency має бути меншою за 500 мс;
дані мають бути доступними з потрібною актуальністю.
Важливо також не плутати:
availability — чи можна скористатися системою;
reliability — наскільки стабільно система працює без збоїв;
durability — чи зберігаються дані та не втрачаються.
Наведений приклад обчислює p50 і p95 latency, throughput за інтервал спостереження та availability за журналом стану сервісу.
const requests = [
{ latencyMs: 120, success: true },
{ latencyMs: 95, success: true },
{ latencyMs: 310, success: true },
{ latencyMs: 80, success: true },
{ latencyMs: 1500, success: false },
{ latencyMs: 210, success: true },
{ latencyMs: 130, success: true },
{ latencyMs: 90, success: true },
{ latencyMs: 450, success: true },
{ latencyMs: 110, success: true }
];
function percentile(values, percentileValue) {
if (values.length === 0) {
return null;
}
const sorted = [...values].sort((a, b) => a - b);
const rank = Math.ceil((percentileValue / 100) * sorted.length);
const index = Math.max(rank - 1, 0);
return sorted[index];
}
const latencies = requests.map((request) => request.latencyMs);
const successfulRequests = requests.filter((request) => request.success).length;
const measurementSeconds = 10;
const throughput = requests.length / measurementSeconds;
console.log(`p50 latency: ${percentile(latencies, 50)} мс`);
console.log(`p95 latency: ${percentile(latencies, 95)} мс`);
console.log(`throughput: ${throughput} запитів/с`);
console.log(
`успішних запитів: ${successfulRequests}/${requests.length}`
);
// Інтервали вказані в хвилинах протягом одного дня.
const uptimeIntervals = [
{ start: 0, end: 480 },
{ start: 485, end: 1440 }
];
const totalMinutes = 24 * 60;
const uptimeMinutes = uptimeIntervals.reduce(
(sum, interval) => sum + (interval.end - interval.start),
0
);
const availability = (uptimeMinutes / totalMinutes) * 100;
console.log(`availability: ${availability.toFixed(3)}%`);У реальній системі такі значення зазвичай збирають із метрик і журналів. Важливо заздалегідь визначити:
що вважається запитом;
які відповіді є успішними;
який період вимірювання використовується;
чи враховується час планових робіт;
як обробляються повторні спроби запитів.
Збільшення кількості паралельних обробників часто підвищує throughput. Але якщо спільний ресурс уже перевантажений, це призводить до:
довших черг;
зростання p95 і p99;
збільшення кількості тайм-аутів;
нестабільної роботи системи.
Тому не слід оптимізувати throughput окремо від latency. Потрібно визначати робочий діапазон, у якому система обробляє потрібну кількість запитів і зберігає прийнятний час відповіді.
Щоб зменшити latency, можна:
розміщувати дані ближче до користувачів;
кешувати часто потрібні результати;
зменшувати обсяг відповіді;
додавати індекси для типових запитів;
використовувати швидші або додаткові ресурси.
Це може збільшити вартість інфраструктури, ускладнити оновлення даних або створити додаткові операційні ризики.
Для підвищення availability часто використовують:
кілька екземплярів сервісу;
резервування критичних компонентів;
автоматичне перемикання на резерв;
розподіл компонентів між різними зонами відмови;
перевірки стану та автоматичне відновлення.
Однак кожен додатковий компонент збільшує складність. Складніша система потребує:
більше моніторингу;
коректного керування конфігурацією;
тестування сценаріїв відмови;
узгодження стану між екземплярами.
Реплікація також може створити компроміс між доступністю та актуальністю даних. Якщо система продовжує приймати операції під час проблем зі зв’язком між репліками, різні компоненти можуть тимчасово бачити різні значення.
Для деяких операцій важливіша доступність: наприклад, система може прийняти подію та обробити її пізніше.
Для інших операцій важливіше негайно отримати узгоджений результат: наприклад, не допустити подвійного списання коштів.
Рішення залежить від домену. Потрібно визначити:
чи може користувач працювати із застарілими даними;
чи дозволені повторні спроби;
чи можна виконати операцію пізніше;
які наслідки матиме тимчасова неузгодженість.
Під час оцінювання конкретного сервісу корисно діяти послідовно:
Визначити сценарій, який вимірюється.
Встановити очікуваний throughput.
Визначити допустимі p95 або p99 latency.
Визначити, яка помилка або затримка означає недоступність.
Провести вимірювання під типовим і піковим навантаженням.
Знайти вузьке місце: CPU, пам’ять, база даних, мережа або зовнішній сервіс.
Перевірити, як система поводиться після перевищення запланованого навантаження.
Окремо перевірити сценарії відмови компонентів.
Метрики потрібно аналізувати разом. Наприклад, збільшення throughput може виглядати позитивно, але якщо одночасно p99 latency зросла з 300 мс до 8 с, користувацький досвід погіршився.
Середнє значення приховує повільні запити. Для користувацьких сценаріїв зазвичай потрібно аналізувати щонайменше p95, а для критичних систем — також p99.
Обробка більшої кількості запитів за секунду не означає, що кожен запит став швидшим. Ці метрики потрібно вимірювати окремо.
200 OK доказом доступностіСистема може повертати успішний HTTP-статус, але не виконувати потрібну бізнес-операцію або повертати непридатні дані. Критерії доступності мають враховувати функціональний результат.
Система може чудово працювати на середньому навантаженні, але втрачати доступність під час піку. Тестування має охоплювати заплановані піки та поведінку після насичення ресурсів.
Збільшення кількості екземплярів API не допоможе, якщо всі вони очікують на одну перевантажену базу даних або зовнішній сервіс.
Зростання черги часто є ранньою ознакою того, що система наближається до межі пропускної здатності. Навіть якщо помилок ще мало, latency уже може швидко погіршуватися.
Latency показує час обробки окремого запиту.
Throughput показує обсяг роботи за одиницю часу.
Availability показує, наскільки часто система доступна відповідно до визначених критеріїв.
Для latency важливо аналізувати p50, p95 і p99, а не лише середнє значення.
Високий throughput не гарантує низької latency.
Після насичення ресурсів збільшення паралельності може спричинити зростання черг і затримок.
Підвищення availability зазвичай потребує резервування, але збільшує складність і вартість.
Систему потрібно проєктувати під конкретні вимоги: прийнятну latency, потрібний throughput і цільову availability.
Компроміси слід оцінювати на основі користувацького сценарію та наслідків відмови.