Розбираю повільний API — де губилися мілісекунди між application, базою та зовнішніми сервісами

💡 Усі статті, обговорення, новини про DevOps — в одному місці. Приєднуйтесь до DevOps спільноти!

Повільний API не завжди означає, що проблема знаходиться в одному невдалому SQL-запиті або в недостатній потужності сервера. На практиці час відповіді REST API складається з кількох етапів: обробки запиту в application, роботи з базою даних, викликів зовнішніх сервісів, серіалізації відповіді та мережевих затримок. Якщо кожен із цих етапів додає навіть невелику затримку, у результаті користувач отримує endpoint, який працює помітно довше, ніж очікується.

Ми розбирали саме такий випадок: API не мав однієї критичної точки відмови, але під навантаженням його поведінка ставала нестабільною. Частина запитів виконувалася нормально, частина займала значно більше часу. Спочатку це виглядало як проблема продуктивності окремого endpoint, але профілювання показало, що затримка накопичується на різних рівнях системи.

Першим кроком було розділити загальний час відповіді на складові. Замість того щоб дивитися лише на час виконання endpoint, ми окремо перевіряли application-код, запити до бази та звернення до зовнішніх сервісів. Це важливо, оскільки середній час відповіді може приховувати зовсім різну картину: endpoint може швидко виконувати бізнес-логіку, але чекати на базу або зовнішній HTTP-запит.

На рівні application виявилося, що частина операцій виконувалася послідовно, хоча між ними не завжди була залежність. У результаті час кількох операцій фактично складався. Також окремо перевірили повторні звернення до одних і тих самих даних та обсяг інформації, який проходив через application перед формуванням відповіді. Навіть без складних алгоритмів такі операції можуть створювати відчутну затримку, особливо коли endpoint викликається часто.

Наступним рівнем стала база даних. Тут проблема також не зводилася до одного «поганого» запиту. Ми перевіряли структуру запитів, кількість звернень до бази та обсяг даних, які вони повертали. Частина запитів виконувалася швидко окремо, але в сукупності створювала зайве навантаження. Для API це особливо критично: проблема проявляється не стільки в одному повільному запиті, скільки в тому, що одночасно виконуються сотні або тисячі таких операцій.

Далі окремо перевірили зовнішні сервіси. Для backend-застосунку зовнішній API є фактично частиною ланцюжка обробки запиту, але контролювати його швидкість ми не можемо. Якщо сервіс відповідає повільніше, application змушений чекати. Без коректних timeout і контролю повторних запитів одна зовнішня затримка може поширитися на значно більшу кількість внутрішніх запитів.

Після цього стало зрозуміло, чому локальні оптимізації не давали очікуваного ефекту. Можна прискорити SQL-запит на кілька мілісекунд, але якщо після нього application чекає на зовнішній сервіс, загальний час відповіді майже не зміниться. Так само збільшення ресурсів application не вирішує проблему, якщо вузьким місцем залишається база або зовнішня інтеграція.

Тому оптимізацію проводили не навколо одного endpoint, а навколо всього ланцюжка обробки запиту. Перевірили порядок виконання операцій, кількість звернень до бази, роботу із зовнішніми сервісами та обробку помилок і таймаутів. Важливо було не просто зменшити час відповіді в ідеальних умовах, а зробити поведінку системи передбачуванішою під навантаженням.

У результаті основним ефектом стала не рекордна цифра в мілісекундах, а стабільність сервісу. API перестав так сильно залежати від випадкових затримок окремих компонентів, а проблеми стало простіше локалізувати за конкретним етапом обробки запиту. Для production-системи це часто важливіше за оптимізацію одного показника latency: передбачувані 300 мс можуть бути кориснішими за 100 мс у нормальних умовах і 3 секунди під навантаженням.

Цей кейс ще раз показав, що продуктивність REST API — це властивість усієї системи, а не окремого фрагмента коду. Application, база даних і зовнішні сервіси працюють як один ланцюжок, тому пошук bottleneck варто починати з вимірювання кожної його частини. Коли видно, де саме витрачається час, оптимізація перестає бути спробою «прискорити код» і перетворюється на послідовну роботу з конкретними вузькими місцями. У нашому випадку саме такий підхід дозволив не просто скоротити окремі затримки, а зробити роботу API стабільнішою та передбачуванішою під навантаженням.

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Розбираю повільний API

Зайшов про це почитати і...нічого. Такий доу останні років *цять, кхе...

Шось якась стаття ніачьом. Якщо нормально зроблена інфраструктура, там і розбиратись нічого, все й так видно.

Підписатись на коментарі