Jak zoptymalizować infrastrukturę produkcyjną Node.js: najlepsze praktyki

Node.js performance optimization guide

Przedmowa

W Forward Email spędziliśmy lata na doskonaleniu naszego środowiska produkcyjnego Node.js. Ten kompleksowy przewodnik dzieli się naszymi sprawdzonymi najlepszymi praktykami wdrażania Node.js w produkcji, koncentrując się na optymalizacji wydajności, monitoringu oraz lekcjach, które wynieśliśmy podczas skalowania aplikacji Node.js do obsługi milionów codziennych transakcji.

Nasza rewolucja optymalizacji wydajności pojedynczego rdzenia o 573%

Kiedy przeszliśmy z procesorów Intel na AMD Ryzen, osiągnęliśmy 573% poprawę wydajności w naszych aplikacjach Node.js. To nie była tylko drobna optymalizacja — zasadniczo zmieniła sposób działania naszych aplikacji Node.js w produkcji i pokazuje, jak ważna jest optymalizacja wydajności pojedynczego rdzenia dla każdej aplikacji Node.js.

Tip

W przypadku najlepszych praktyk wdrażania Node.js w produkcji wybór sprzętu jest kluczowy. Specjalnie wybraliśmy hosting DataPacket ze względu na dostępność AMD Ryzen, ponieważ wydajność pojedynczego rdzenia jest kluczowa dla aplikacji Node.js, gdyż wykonywanie JavaScript jest jednowątkowe.

Dlaczego optymalizacja wydajności pojedynczego rdzenia ma znaczenie dla Node.js

Nasza migracja z Intela na AMD Ryzen zaowocowała:

  • 573% poprawą wydajności w przetwarzaniu żądań (udokumentowane w GitHub Issue #1519 na naszej stronie statusowej)
  • Eliminacją opóźnień w przetwarzaniu do niemal natychmiastowych odpowiedzi (wspomniane w GitHub Issue #298)
  • Lepszym stosunkiem ceny do wydajności dla środowisk produkcyjnych Node.js
  • Poprawą czasów odpowiedzi na wszystkich punktach końcowych naszych aplikacji

Wzrost wydajności był tak znaczący, że obecnie uważamy procesory AMD Ryzen za niezbędne dla każdego poważnego wdrożenia produkcyjnego Node.js, niezależnie od tego, czy uruchamiasz aplikacje webowe, API, mikrousługi czy inne obciążenia Node.js.

Aby uzyskać więcej szczegółów na temat naszych wyborów infrastruktury, sprawdź:

Konfiguracja środowiska produkcyjnego Node.js: Nasz stos technologiczny

Nasze najlepsze praktyki wdrażania Node.js w produkcji obejmują świadome wybory technologiczne oparte na wieloletnim doświadczeniu produkcyjnym. Oto co używamy i dlaczego te wybory mają zastosowanie do każdej aplikacji Node.js:

Menedżer pakietów: pnpm dla efektywności produkcyjnej

Co używamy: pnpm (przypięta wersja)

Wybraliśmy pnpm zamiast npm i yarn do naszego środowiska produkcyjnego Node.js, ponieważ:

  • Szybsze czasy instalacji w pipeline’ach CI/CD
  • Efektywność miejsca na dysku dzięki twardemu linkowaniu
  • Ścisłe rozwiązywanie zależności, które zapobiega pojawianiu się ukrytych zależności
  • Lepsza wydajność w wdrożeniach produkcyjnych

Note

W ramach naszych najlepszych praktyk wdrażania Node.js w produkcji przypinamy dokładne wersje kluczowych narzędzi, takich jak pnpm, aby zapewnić spójne zachowanie we wszystkich środowiskach i na maszynach członków zespołu.

Szczegóły implementacji:

Framework webowy: Koa dla nowoczesnej produkcji Node.js

Co używamy:

  • @koa/router
  • @koa/multer
  • @ladjs/koa-simple-ratelimit Wybraliśmy Koa zamiast Express dla naszej infrastruktury produkcyjnej Node.js ze względu na nowoczesne wsparcie async/await oraz czyściejszą kompozycję middleware. Nasz założyciel Nick Baugh przyczynił się do rozwoju zarówno Express, jak i Koa, co dało nam głębokie zrozumienie obu frameworków pod kątem zastosowań produkcyjnych.

Te wzorce mają zastosowanie niezależnie od tego, czy budujesz REST API, serwery GraphQL, aplikacje webowe czy mikrousługi.

Nasze przykłady implementacji:

Przetwarzanie zadań w tle: Bree dla niezawodności produkcyjnej

Co używamy: bree scheduler

Stworzyliśmy i utrzymujemy Bree, ponieważ istniejące harmonogramy zadań nie spełniały naszych wymagań dotyczących wsparcia wątków roboczych oraz nowoczesnych funkcji JavaScript w środowiskach produkcyjnych Node.js. Dotyczy to każdej aplikacji Node.js, która potrzebuje przetwarzania w tle, zadań zaplanowanych lub wątków roboczych.

Nasze przykłady implementacji:

Obsługa błędów: @hapi/boom dla niezawodności produkcyjnej

Co używamy: @hapi/boom

Używamy @hapi/boom do strukturalnych odpowiedzi błędów w naszych produkcyjnych aplikacjach Node.js. Ten wzorzec działa dla każdej aplikacji Node.js, która potrzebuje spójnej obsługi błędów.

Nasze przykłady implementacji:

Jak monitorować aplikacje Node.js w produkcji

Nasze podejście do monitorowania aplikacji Node.js w produkcji ewoluowało przez lata uruchamiania aplikacji na dużą skalę. Wdrażamy monitoring na wielu warstwach, aby zapewnić niezawodność i wydajność dla każdego typu aplikacji Node.js.

Monitorowanie produkcyjne Node.js na poziomie systemu

Nasza podstawowa implementacja: helpers/monitor-server.js

Co używamy: node-os-utils

Nasze progi monitorowania produkcyjnego (z naszego rzeczywistego kodu produkcyjnego):

  • Limit rozmiaru sterty 2GB z automatycznymi alertami
  • Próg ostrzeżenia 25% użycia pamięci
  • Próg alertu 80% użycia CPU
  • Próg ostrzeżenia 75% użycia dysku

Warning

Te progi działają dla naszej konkretnej konfiguracji sprzętowej. Przy wdrażaniu monitorowania produkcyjnego Node.js zapoznaj się z implementacją monitor-server.js, aby zrozumieć dokładną logikę i dostosować wartości do swojego środowiska.

Monitorowanie produkcyjne Node.js na poziomie aplikacji

Nasza klasyfikacja błędów: helpers/is-code-bug.js

Ten pomocnik rozróżnia:

  • Rzeczywiste błędy w kodzie, które wymagają natychmiastowej uwagi
  • Błędy użytkownika, które są oczekiwanym zachowaniem
  • Awarię usług zewnętrznych, których nie możemy kontrolować

Ten wzorzec ma zastosowanie do każdej aplikacji Node.js – aplikacji webowych, API, mikrousług lub usług działających w tle. Nasza implementacja logowania: helpers/logger.js

Wprowadzamy kompleksowe zaciemnianie pól, aby chronić wrażliwe informacje, jednocześnie zachowując przydatne możliwości debugowania w naszym środowisku produkcyjnym Node.js.

Monitorowanie specyficzne dla aplikacji

Nasze implementacje serwerów:

Monitorowanie kolejki: Wprowadzamy limity kolejki 5GB oraz timeouty 180 sekund na przetwarzanie żądań, aby zapobiec wyczerpaniu zasobów. Te wzorce mają zastosowanie do każdej aplikacji Node.js z kolejkami lub przetwarzaniem w tle.

Monitorowanie produkcji Node.js z PM2 Health Checks

Udoskonaliliśmy nasze środowisko produkcyjne Node.js z PM2 na podstawie wieloletniego doświadczenia produkcyjnego. Nasze health checki PM2 są niezbędne do utrzymania niezawodności w każdej aplikacji Node.js.

Nasz system health checków PM2

Nasza podstawowa implementacja: jobs/check-pm2.js

Nasze monitorowanie produkcji Node.js z health checkami PM2 obejmuje:

  • Uruchamianie co 20 minut za pomocą harmonogramu cron
  • Wymaga minimum 15 minut czasu działania przed uznaniem procesu za zdrowy
  • Weryfikuje status procesu i zużycie pamięci
  • Automatycznie restartuje nieudane procesy
  • Zapobiega pętlom restartów dzięki inteligentnemu sprawdzaniu stanu

Caution

Dla najlepszych praktyk wdrożenia produkcyjnego Node.js wymagamy 15+ minut czasu działania przed uznaniem procesu za zdrowy, aby uniknąć pętli restartów. Zapobiega to kaskadowym awariom, gdy procesy mają problemy z pamięcią lub inne problemy.

Nasza konfiguracja produkcyjna PM2

Nasza konfiguracja ekosystemu: Zapoznaj się z naszymi plikami startowymi serwera dla środowiska produkcyjnego Node.js:

Te wzorce mają zastosowanie niezależnie od tego, czy uruchamiasz aplikacje Express, serwery Koa, API GraphQL czy inne aplikacje Node.js.

Zautomatyzowane wdrożenie PM2

Wdrożenie PM2: ansible/playbooks/node.yml

Automatyzujemy całe nasze środowisko PM2 za pomocą Ansible, aby zapewnić spójne wdrożenia produkcyjne Node.js na wszystkich naszych serwerach.

System obsługi i klasyfikacji błędów produkcyjnych

Jedną z naszych najcenniejszych najlepszych praktyk wdrożenia produkcyjnego Node.js jest inteligentna klasyfikacja błędów, która ma zastosowanie do każdej aplikacji Node.js:

Nasza implementacja isCodeBug dla produkcji

Źródło: helpers/is-code-bug.js

Ten helper zapewnia inteligentną klasyfikację błędów dla aplikacji Node.js w produkcji, aby:

  • Priorytetyzować rzeczywiste błędy nad błędami użytkownika
  • Poprawić naszą reakcję na incydenty poprzez skupienie się na prawdziwych problemach
  • Zmniejszyć zmęczenie alertami wynikające z oczekiwanych błędów użytkownika
  • Lepsze zrozumienie problemów aplikacji vs generowanych przez użytkownika

Ten wzorzec działa dla każdej aplikacji Node.js – niezależnie czy tworzysz strony e-commerce, platformy SaaS, API czy mikrousługi.

Integracja z naszym logowaniem produkcyjnym

Nasza integracja loggera: helpers/logger.js Nasz logger używa isCodeBug do określania poziomów alertów i redakcji pól, zapewniając, że otrzymujemy powiadomienia o prawdziwych problemach, jednocześnie filtrując szumy w naszym środowisku produkcyjnym Node.js.

Dowiedz się więcej o naszych wzorcach obsługi błędów:

Zaawansowane debugowanie wydajności z v8-profiler-next i cpupro

Używamy zaawansowanych narzędzi profilujących do analizy zrzutów sterty i debugowania problemów OOM (Out of Memory), wąskich gardeł wydajności oraz problemów z pamięcią Node.js w naszym środowisku produkcyjnym. Te narzędzia są niezbędne dla każdej aplikacji Node.js doświadczającej wycieków pamięci lub problemów z wydajnością.

Nasze podejście do profilowania w produkcji Node.js

Narzędzia, które polecamy:

  • v8-profiler-next - Do generowania zrzutów sterty i profili CPU
  • cpupro - Do analizy profili CPU i zrzutów sterty

Tip

Używamy v8-profiler-next i cpupro razem, aby stworzyć kompletny workflow debugowania wydajności dla naszych aplikacji Node.js. To połączenie pomaga nam identyfikować wycieki pamięci, wąskie gardła wydajności i optymalizować nasz kod produkcyjny.

Jak implementujemy analizę zrzutów sterty

Nasza implementacja monitoringu: helpers/monitor-server.js

Nasz monitoring produkcyjny obejmuje automatyczne generowanie zrzutów sterty, gdy przekroczone zostaną progi pamięci. Pomaga to debugować problemy OOM zanim spowodują awarie aplikacji.

Kluczowe wzorce implementacji:

  • Automatyczne zrzuty gdy rozmiar sterty przekracza próg 2GB
  • Profilowanie na sygnał do analizy na żądanie w produkcji
  • Polityki retencji do zarządzania przechowywaniem zrzutów
  • Integracja z naszymi zadaniami czyszczącymi do automatycznej konserwacji

Workflow debugowania wydajności

Przeanalizuj naszą rzeczywistą implementację:

Do analizy zrzutów sterty:

  1. Zainstaluj v8-profiler-next do generowania zrzutów
  2. Użyj cpupro do analizy wygenerowanych zrzutów
  3. Wdroż progi monitoringu podobne do naszego monitor-server.js
  4. Skonfiguruj automatyczne czyszczenie do zarządzania przechowywaniem zrzutów
  5. Utwórz obsługę sygnałów do profilowania na żądanie w produkcji

Do profilowania CPU:

  1. Generuj profile CPU podczas okresów dużego obciążenia
  2. Analizuj za pomocą cpupro aby zidentyfikować wąskie gardła
  3. Skup się na gorących ścieżkach i możliwościach optymalizacji
  4. Monitoruj przed i po wprowadzeniu usprawnień wydajności

Warning

Generowanie zrzutów sterty i profili CPU może wpływać na wydajność. Zalecamy wdrożenie ograniczeń i włączanie profilowania tylko podczas badania konkretnych problemów lub w oknach konserwacyjnych.

Integracja z naszym monitoringiem produkcyjnym

Nasze narzędzia profilujące integrują się z naszą szerszą strategią monitoringu:

  • Automatyczne wyzwalanie na podstawie progów pamięci/CPU
  • Integracja alertów gdy wykrywane są problemy z wydajnością
  • Analiza historyczna do śledzenia trendów wydajności w czasie
  • Korelacja z metrykami aplikacji dla kompleksowego debugowania To podejście pomogło nam zidentyfikować i rozwiązać wycieki pamięci, zoptymalizować gorące ścieżki kodu oraz utrzymać stabilną wydajność w naszym środowisku produkcyjnym Node.js.

Bezpieczeństwo infrastruktury produkcyjnej Node.js

Wdrażamy kompleksowe zabezpieczenia dla naszej infrastruktury produkcyjnej Node.js za pomocą automatyzacji Ansible. Te praktyki mają zastosowanie do każdej aplikacji Node.js:

Bezpieczeństwo na poziomie systemu dla produkcji Node.js

Nasza implementacja Ansible: ansible/playbooks/security.yml

Nasze kluczowe środki bezpieczeństwa dla środowisk produkcyjnych Node.js:

  • Wyłączona pamięć wymiany (swap), aby zapobiec zapisywaniu wrażliwych danych na dysku
  • Wyłączone zrzuty pamięci (core dumps), aby zapobiec wyciekom pamięci zawierającym wrażliwe informacje
  • Zablokowane pamięci USB, aby zapobiec nieautoryzowanemu dostępowi do danych
  • Dostosowanie parametrów jądra zarówno pod kątem bezpieczeństwa, jak i wydajności

Warning

Podczas wdrażania najlepszych praktyk produkcyjnego wdrożenia Node.js wyłączenie pamięci wymiany może spowodować zabijanie procesów z powodu braku pamięci, jeśli aplikacja przekroczy dostępną pamięć RAM. Monitorujemy zużycie pamięci uważnie i odpowiednio dobieramy rozmiar naszych serwerów.

Bezpieczeństwo aplikacji dla aplikacji Node.js

Nasze redagowanie pól logów: helpers/logger.js

Redagujemy wrażliwe pola w logach, w tym hasła, tokeny, klucze API oraz dane osobowe. Chroni to prywatność użytkowników, jednocześnie zachowując możliwości debugowania w każdym środowisku produkcyjnym Node.js.

Automatyzacja bezpieczeństwa infrastruktury

Nasza kompletna konfiguracja Ansible dla produkcji Node.js:

Nasze materiały dotyczące bezpieczeństwa

Dowiedz się więcej o naszym podejściu do bezpieczeństwa:

Architektura bazy danych dla aplikacji Node.js

Używamy hybrydowego podejścia do baz danych zoptymalizowanego dla naszych aplikacji Node.js. Te wzorce można dostosować do każdej aplikacji Node.js:

Implementacja SQLite dla produkcji Node.js

Co używamy:

Nasza konfiguracja: ansible/playbooks/sqlite.yml

Używamy SQLite do danych specyficznych dla użytkownika w naszych aplikacjach Node.js, ponieważ zapewnia:

  • Izolację danych dla każdego użytkownika/najemcy
  • Lepszą wydajność dla zapytań jednoosobowych
  • Uproszczone tworzenie kopii zapasowych i migracje
  • Zmniejszoną złożoność w porównaniu do współdzielonych baz danych

Ten wzorzec sprawdza się dobrze w aplikacjach SaaS, systemach wielonajemcowych lub każdej aplikacji Node.js, która potrzebuje izolacji danych.

Implementacja MongoDB dla produkcji Node.js

Co używamy:

Nasza konfiguracja: config/mongoose.js

Używamy MongoDB do danych aplikacji w naszym środowisku produkcyjnym Node.js, ponieważ zapewnia:

  • Elastyczny schemat dla ewoluujących struktur danych
  • Lepszą wydajność dla złożonych zapytań
  • Możliwości skalowania poziomego
  • Bogaty język zapytań

Note

Nasze podejście hybrydowe optymalizuje się pod nasz konkretny przypadek użycia. Przeanalizuj rzeczywiste wzorce użycia bazy danych w kodzie, aby zrozumieć, czy to podejście pasuje do potrzeb Twojej aplikacji Node.js.

Przetwarzanie zadań w tle w produkcji Node.js

Zbudowaliśmy naszą architekturę zadań w tle wokół Bree dla niezawodnego wdrożenia produkcyjnego Node.js. Dotyczy to każdej aplikacji Node.js, która potrzebuje przetwarzania w tle:

Nasza konfiguracja serwera Bree dla produkcji

Nasza główna implementacja: bree.js

Nasze wdrożenie Ansible: ansible/playbooks/bree.yml

Przykłady zadań produkcyjnych

Monitorowanie stanu: jobs/check-pm2.js

Automatyczne sprzątanie: jobs/cleanup-tmp.js

Wszystkie nasze zadania: Przeglądaj nasz kompletny katalog zadań

Te wzorce dotyczą każdej aplikacji Node.js, która potrzebuje:

  • Zaplanowanych zadań (przetwarzanie danych, raporty, sprzątanie)
  • Przetwarzania w tle (zmiana rozmiaru obrazów, wysyłanie e-maili, importy danych)
  • Monitorowania stanu i konserwacji
  • Wykorzystania wątków roboczych do zadań intensywnych obliczeniowo

Nasze wzorce harmonogramowania zadań dla produkcji Node.js

Przeanalizuj nasze rzeczywiste wzorce harmonogramowania zadań w katalogu zadań, aby zrozumieć:

  • Jak implementujemy harmonogramowanie podobne do cron w produkcji Node.js
  • Naszą obsługę błędów i logikę ponawiania prób
  • Jak używamy wątków roboczych do zadań intensywnych obliczeniowo

Zautomatyzowana konserwacja dla produkcyjnych aplikacji Node.js

Wdrażamy proaktywną konserwację, aby zapobiegać typowym problemom produkcyjnym Node.js. Te wzorce dotyczą każdej aplikacji Node.js:

Nasza implementacja sprzątania

Źródło: jobs/cleanup-tmp.js

Nasza zautomatyzowana konserwacja dla produkcyjnych aplikacji Node.js obejmuje:

  • Pliki tymczasowe starsze niż 24 godziny
  • Pliki dziennika przekraczające limity retencji
  • Pliki cache i dane tymczasowe
  • Przesłane pliki, które nie są już potrzebne
  • Zrzuty sterty z debugowania wydajności

Te wzorce dotyczą każdej aplikacji Node.js, która generuje pliki tymczasowe, dzienniki lub dane cache.

Zarządzanie miejscem na dysku dla produkcji Node.js

Nasze progi monitorowania: helpers/monitor-server.js

  • Limity kolejki dla przetwarzania w tle
  • Ostrzeżenie przy 75% wykorzystania dysku
  • Automatyczne sprzątanie po przekroczeniu progów

Automatyzacja konserwacji infrastruktury

Nasza automatyzacja Ansible dla produkcji Node.js:

Przewodnik po implementacji wdrożenia produkcyjnego Node.js

Study Our Actual Code for Production Best Practices

Zacznij od tych kluczowych plików do konfiguracji środowiska produkcyjnego Node.js:

  1. Konfiguracja: config/index.js
  2. Monitorowanie: helpers/monitor-server.js
  3. Obsługa błędów: helpers/is-code-bug.js
  4. Logowanie: helpers/logger.js
  5. Stan procesu: jobs/check-pm2.js

Learn from Our Blog Posts

Nasze techniczne przewodniki wdrożeniowe dla produkcji Node.js:

Infrastructure Automation for Node.js Production

Nasze playbooki Ansible do nauki wdrożenia produkcyjnego Node.js:

Our Case Studies

Nasze wdrożenia korporacyjne:

Conclusion: Node.js Production Deployment Best Practices

Nasza infrastruktura produkcyjna Node.js pokazuje, że aplikacje Node.js mogą osiągnąć niezawodność klasy korporacyjnej dzięki:

  • Sprawdzonym wyborom sprzętu (AMD Ryzen dla 573% optymalizacji wydajności pojedynczego rdzenia)
  • Przetestowanemu monitorowaniu produkcji Node.js z określonymi progami i automatycznymi reakcjami
  • Inteligentnej klasyfikacji błędów w celu poprawy reakcji na incydenty w środowiskach produkcyjnych
  • Zaawansowanemu debugowaniu wydajności z użyciem v8-profiler-next i cpupro dla zapobiegania OOM
  • Kompleksowemu wzmacnianiu bezpieczeństwa poprzez automatyzację Ansible
  • Hybrydowej architekturze bazy danych zoptymalizowanej pod potrzeby aplikacji
  • Automatycznej konserwacji zapobiegającej typowym problemom produkcyjnym Node.js

Kluczowa wskazówka: Studiuj nasze rzeczywiste pliki implementacyjne i wpisy na blogu zamiast stosować ogólne najlepsze praktyki. Nasza baza kodu dostarcza wzorców z prawdziwego świata dla wdrożeń produkcyjnych Node.js, które można dostosować do każdej aplikacji Node.js – aplikacji webowych, API, mikrousług lub usług działających w tle.

Complete Resource List for Node.js Production

Our Core Implementation Files

Nasze implementacje serwerów

Nasza automatyzacja infrastruktury

Nasze techniczne wpisy na blogu

Nasze studia przypadków dla przedsiębiorstw