Language switcher

Light

Dark

Node.js | Як оптимізувати свій API
Опубліковано Shchelko

Способи оптимізації застосунків на Node.js включають:

  1. Використання останньої версії Node.js. Нові версії Node.js зазвичай включають покращення продуктивності й виправлення помилок.
  2. Використання профайлера. Профайлер може допомогти визначити частини вашого коду, які заважають продуктивності, як-от сповільнені виклики функцій або витоки пам’яті.
  3. Мінімізація використання синхронних функцій. Синхронні функції блокують цикл подій, виключаючи виконання іншого коду. Натомість слід використовувати асинхронні функції, як-от ті, що надаються ключовими словами  async та await.
  4. Використання мережі доправлення контенту (CDN). CDN може допомогти розподілити статичні ресурси застосунку, розвантажуючи ваш сервер.
  5. Використання зворотного проксі-сервера. Зворотний проксі-сервер на кшталт NGINX або HAProxy може допомогти з балансуванням навантаження та завершенням SSL, вивільняючи ваш Node.js сервер для інших завдань.
  6. Використання кешування. Кешування може підвищити продуктивність вашого застосунку, зберігаючи в пам’яті результати затратних операцій, як-от запитів до бази даних.
  7. Оптимізація запитів до бази даних.
  8. Використання менеджера процесів, як-от pm2, для кращого керування процесами.

Розглянемо кожен метод детальніше.

1. Використання останньої версії Node.js, яка зазвичай включає покращення продуктивності й виправлення помилок.

Використання найновішої версії Node.js може допомогти покращити продуктивність і безпеку. Розробники Node.js наполегливо працюють над поліпшенням продуктивності платформи. Оновлення до останньої версії зазвичай передбачає доступ до нових функцій і підвищення продуктивності. Однак перед оновленням важливо переконатися, що ваш застосунок сумісний з новою версією Node.js.

Також обов’язково слідкуйте за примітками до випусків  Node.js, у яких перелічуються нові функції, виправлення помилок і покращення продуктивності в новій версії. Це допоможе зрозуміти, на які частини вашого застосунку може вплинути оновлення.

2. Використання профайлера, який може допомогти визначити частини вашого коду, які заважають продуктивності.

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

Для Node.js доступно кілька профайлерів, як-от вбудований профайлер у Node.js, інспектор v8 та node inspector. Ось деякі популярні сторонні профайлери:

  • node-clinic
  • nodetime
  • strong-trace
  • node-memwatch

Також не забувайте, що для моніторингу продуктивності JavaScript на стороні клієнта можна використовувати інструменти продуктивності у браузері.

Корисно профілювати застосунок в різних сценаріях, як-от під навантаженням, щоб краще розуміти його поведінку в різних умовах.

3. Мінімізація використання синхронних функцій і надання переваги асинхронним функціям, як-от ті, що надаються ключовими словами  async та await.

У Node.js цикл подій керує виконанням JavaScript коду. Синхронні функції блокують його, запобігаючи виконанню іншого коду. Це може призвести до низької продуктивності та сповільнених відгуків. На відміну від них, асинхронні функції дозволяють виконувати інший код під час їх роботи, що може поліпшити загальну продуктивність вашого застосунку.

Ключові слова async/await – це спосіб написання асинхронного коду, який виглядає та поводиться як синхронний код. Вони дозволяють писати асинхронний код за допомогою знайомого синтаксису, полегшуючи його розуміння та підтримку.

Наприклад, замість використання шаблону зворотного виклику:

Можна використати async/await таким чином:

Зазначимо, що не всі функції є асинхронними і не всі синхронні функції створюють проблеми для застосунку. Варто спочатку ретельно оцінити варіант використання, і лише потім вирішувати, чи робити функцію асинхронною чи ні.

Варто також зазначити, що не всі частини вашого застосунку виграють від використання асинхронних функцій. Наприклад, операції, пов’язані з вводом-виводом, як-от читання/запис із файлу або підключення до бази даних, підходять для асинхронних функцій. А операції, пов’язані з ЦП, як-от важкі обчислення, не підходять.

4. Використання CDN, яка може допомогти розподілити статичні ресурси застосунку та розвантажити сервер.

Мережа доправлення контенту (CDN) – це мережа географічно розосереджених серверів, призначена для доставки користувачам контенту у вигляді зображень, відео та інших статичних ресурсів, прагнучи до високої доступності та швидкості.

Коли користувач запитує статичний ресурс у вашому застосунку, запит направляється на найближчий сервер CDN, і він доставляє потрібний ресурс користувачеві. Це може зменшити навантаження на ваш сервер та покращити продуктивність вашого застосунку для користувачів, які знаходяться далеко від вашого сервера.

CDN пропонує додаткові переваги:

  • Покращена безпека завдяки захисту від DDoS і розвантаженню SSL
  • Кешування статичних ресурсів, що може зменшити кількість запитів до вашого вихідного сервера.
  • Зменшення навантаження на вихідний сервер і поліпшення масштабованості вашого застосунку.

Є можливість обирати з-поміж багатьох постачальників CDN, таких як Cloudflare, Amazon CloudFront, Akamai та інших, відповідно до потреб та бюджету.

Варто зазначити, що використання CDN є доцільним не для всіх типів застосунків. Наприклад, якщо ваш обслуговує невелику кількість користувачів, більшість з яких знаходяться в тому ж місці, що й вихідний сервер, використання CDN не принесе значних переваг.

5. Використання зворотного проксі-сервера, який може допомогти з балансуванням навантаження та завершенням SSL, вивільняючи ваш Node.js сервер для інших завдань.

Зворотний проксі-сервер – це сервер, який знаходиться перед одним або кількома вебсерверами та пересилає вхідні запити на відповідний сервер. Зворотні проксі-сервери можна використовувати для різноманітних завдань, таких як балансування навантаження, завершення SSL і кешування.

Балансування навантаження – це процес розподілу вхідного трафіку між кількома серверами таким чином, щоб не перевантажити жоден з них. Зворотні проксі-сервери можуть робити це за різними алгоритмами, як-от циклічним або принципом найменшого числа з’єднань.

“Завершення SSL” позначає процес обробки SSL-шифрування та дешифрування до того, як запит дістанеться до вебсерверів. Здійснюючи завершення SSL на зворотному проксі-сервері, ви сприяєте обробці незашифрованих запитів вебсерверами. Це знижує навантаження на вебсервери та підвищує продуктивність.

Кешуванням називають зберігання часто запитуваних даних у пам’яті з тим, щоб їх можна було швидко видавати, не генеруючи відгук з нуля. Зворотні проксі-сервери можуть кешувати відповіді від вебсерверів, зменшуючи навантаження на вебсервери та покращуючи продуктивність застосунку.

NGINX і HAProxy – це популярні зворотні проксі-сервери з відкритим кодом, які можуть допомогти з цими завданнями. Обидва широко використовуються, легко налаштовуються та мають активні спільноти.

Варто згадати й про інші доступні зворотні проксі-сервери, як-от Apache, Traefik тощо. Аналіз вимог вашого застосунку допоможе обрати підхожий.

6. Використання кешування, яке може підвищити продуктивність вашого застосунку.

Кешування зберігає у пам’яті результати затратних операцій на кшталт запитів до бази даних, щоб їх можна було швидко видавати, не генеруючи кожного разу відгук з нуля. Кешування таким чином може значно підвищити продуктивність вашого застосунку, особливо при роботі з даними, які часто запитуються.

Можна застосовувати різні типи кешування:

  • Кешування в пам’яті. Цей спосіб зберігає дані в пам’яті сервера додатку. Він швидкий, але нестабільний: якщо сервер перезапустять, дані будуть втрачені.
  • Кешування на диску. Дані зберігаються на диску сервера додатку. Це кешування повільніше, ніж у пам’яті, але більш тривке.
  • Розподілене кешування. Дані розподіляються для зберігання між кількома серверами. Це корисно для застосунків, які масштабуються горизонтально на кількох серверах.

Існує кілька рішень для кешування для Node.js, включаючи memcached і redis. Ці два здійснюють кешування в пам’яті та сприяють швидкому доступу до часто запитуваних даних.

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

Крім того, корисно вимірювати продуктивність застосунку із кешуванням і без, аби мати чітке уявлення про переваги, які воно приносить.

7. Оптимізація запитів до бази даних.

Оптимізація запитів до бази даних є ключовим кроком в оптимізації застосунків на Node.js. Погано написані або неефективні запити можуть спричинити низьку продуктивність і надмірне споживання ресурсів, а це веде до погіршення досвіду користувача.

Існує кілька способів оптимізації запитів до бази даних, наприклад:

  • Вживання індексів. Індекси можуть покращити продуктивність запитів, допомагаючи базі даних швидко знаходити необхідні дані. Важливо використовувати правильні індекси для запитів, оскільки надмір індексів може знизити продуктивність.
  • Використання підготовлених операторів. Підготовлені оператори можуть підвищити продуктивність запитів, адже вони дозволяють базі даних повторно використовувати план виконання запиту, зменшуючи витрати на парсинг під час кожного його виконання.
  • Використання пагінації. Отримання всіх даних одночасно може бути повільним і споживати багато пам’яті. Пагінація передбачає отримання певного числа рядків за раз, що зменшує навантаження на базу даних і покращує продуктивність застосунку.
  • Кешування. Кешування результатів часто виконуваних запитів усуває необхідність кожного разу звертатись до бази даних, що теж сприяє підвищенню продуктивності.
  • Використання плану-пояснення. У багатьох базах даних є функція плану-пояснення, яка дозволяє побачити, як база даних виконає запит. Це може допомогти визначити перешкоди продуктивності та взити відповідних заходів.
  • Застосування ORM (Object-relational mapping) бібліотек для обробки запитів до бази даних. ORM бібліотеки, як-от sequelize або mongoose, забезпечують вищий рівень абстракції і пропонують багато способів оптимізації продуктивності.

Варто пам’ятати, що різні бази даних мають різні характеристики продуктивності та можуть потребувати різних методів оптимізації. Потрібно добре розуміти характеристики конкретної бази даних, аби використовувати її якнайефективніше.

8. Використання менеджера процесів для кращого керування процесами.

Використання менеджера процесів на кшталт pm2 може допомогти покращити керування процесами вашого застосунку на Node.js.

pm2 – це популярний менеджер процесів для застосунків на Node.js. Він дозволяє запускати кілька застосунків на одному сервері, виконувати запуск, зупинку та перезапуск програм, та слідкувати за станом застосунків.

Ось деякі з функцій, які пропонує pm2:

  • Автоматичний перезапуск. pm2 автоматично перезапустить застосунок, якщо він вийде з ладу або зупиниться.
  • Балансування навантаження. pm2 може автоматично балансувати навантаження між кількома серверами одного застосунку.
  • Моніторинг. pm2 може стежити за працездатністю, включаючи використання процесора та пам’яті, і надавати детальну інформацію про стан застосунків.
  • Керування журналами. pm2 може керувати журналами для вашого застосунку, включаючи ротацію журналів, і зводити разом журнали з кількох серверів одного застосунку.

Використовуючи менеджер процесів на кшталт pm2, ви можете підвищити надійність і продуктивність своїх застосунків на Node.js. Він також може допомогти вам підтримувати роботу застосунку, навіть коли сервер перезавантажується.

pm2 – не єдиний менеджер процесів, доступний для Node.js. Є також, наприклад, forever та nodemon. Варто оцінити функції різних менеджерів процесів та обрати той, який найкраще відповідає вимогам вашого застосунку.

Це лише кілька прикладів того, як можна оптимізувати застосунки на Node.js.