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

Przedmowa

W Forward Email spędziliśmy lata na udoskonalaniu konfiguracji środowiska produkcyjnego Node.js. Ten kompleksowy przewodnik przedstawia nasze sprawdzone w boju najlepsze praktyki wdrażania produkcyjnego Node.js, skupiając się na optymalizacji wydajności, monitorowaniu i wnioskach, których nauczyliśmy się, skalując aplikacje Node.js w celu obsługi milionów codziennych transakcji.

Nasza rewolucja w optymalizacji wydajności pojedynczego rdzenia o 573%

Kiedy przeszliśmy z procesorów Intel na procesory AMD Ryzen, osiągnęliśmy 573% poprawa wydajności w naszych aplikacjach Node.js. Nie była to tylko drobna optymalizacja — zasadniczo zmieniła sposób działania naszych aplikacji Node.js w produkcji i pokazuje znaczenie optymalizacji wydajności pojedynczego rdzenia dla dowolnej aplikacji Node.js.

[!TIP] W przypadku najlepszych praktyk wdrażania produkcyjnego Node.js wybór sprzętu ma kluczowe znaczenie. Wybraliśmy hosting DataPacket ze względu na dostępność AMD Ryzen, ponieważ wydajność pojedynczego rdzenia jest kluczowa dla aplikacji Node.js, ponieważ wykonywanie JavaScript jest jednowątkowe.

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

Nasza migracja z procesorów Intel na procesory AMD Ryzen przyniosła następujące efekty:

  • 573% poprawa wydajności w przetwarzaniu żądań (udokumentowane w nasza strona ze statusem GitHub Issue #1519)
  • Wyeliminowano opóźnienia w przetwarzaniu do niemal natychmiastowych reakcji (wspomnianych w Problem GitHub nr 298)
  • Lepszy stosunek ceny do wydajności dla środowisk produkcyjnych Node.js
  • Skrócony czas reakcji we wszystkich naszych punktach końcowych aplikacji

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

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

Konfiguracja środowiska produkcyjnego Node.js: Nasz zestaw technologii

Nasze najlepsze praktyki wdrażania produkcyjnego Node.js obejmują świadome wybory technologiczne oparte na wieloletnim doświadczeniu produkcyjnym. Oto, czego używamy i dlaczego te wybory mają zastosowanie do dowolnej aplikacji Node.js:

Menedżer pakietów: pnpm dla wydajności produkcji

Z czego korzystamy: pnpm (wersja przypięta)

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

  • Krótszy czas instalacji w procesach CI/CD
  • Efektywność przestrzeni dyskowej poprzez twarde linkowanie
  • Ścisłe rozwiązywanie zależności co zapobiega uzależnieniom urojonym
  • Lepsza wydajność wdrożeń produkcyjnych

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

Szczegóły wdrożenia:

Framework sieciowy: Koa dla nowoczesnej produkcji Node.js

Z czego korzystamy:

Wybraliśmy Koa zamiast Express dla naszej infrastruktury produkcyjnej Node.js ze względu na nowoczesne wsparcie async/await i czystszą kompozycję middleware. Nasz założyciel Nick Baugh przyczynił się do rozwoju zarówno Express, jak i Koa, dając nam głęboki wgląd w oba frameworki do użytku produkcyjnego.

Wzorce te mają zastosowanie niezależnie od tego, czy tworzysz interfejsy API REST, serwery GraphQL, aplikacje internetowe czy mikrousługi.

Przykłady naszych wdrożeń:

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

Z czego korzystamy: bree harmonogramista

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

Przykłady naszych wdrożeń:

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

Z czego korzystamy: @hapi/boom

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

Przykłady naszych wdrożeń:

Jak monitorować aplikacje Node.js w środowisku produkcyjnym

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

Monitorowanie produkcji Node.js na poziomie systemu

Nasza główna implementacja: helpers/monitor-server.js

Z czego korzystamy: node-os-utils

Nasze progi monitorowania produkcji (na podstawie naszego rzeczywistego kodu produkcyjnego):

  • Limit rozmiaru sterty 2 GB z automatycznymi alertami
  • 25% wykorzystania pamięci próg ostrzegawczy
  • 80% wykorzystania procesora próg alarmowy
  • 75% wykorzystania dysku próg ostrzegawczy

[!WARNING] Te progi działają dla naszej konkretnej konfiguracji sprzętowej. Podczas wdrażania monitoringu produkcji Node.js, przejrzyj naszą implementację monitor-server.js, aby zrozumieć dokładną logikę i dostosować wartości do swojej konfiguracji.

Monitorowanie na poziomie aplikacji dla produkcji Node.js

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

Ten pomocnik rozróżnia:

  • Rzeczywiste błędy kodu które wymagają natychmiastowej uwagi
  • Błędy użytkownika które są oczekiwanym zachowaniem
  • Awarie usług zewnętrznych że nie możemy kontrolować

Ten wzorzec ma zastosowanie w przypadku dowolnej aplikacji Node.js — aplikacji internetowych, interfejsów API, mikrousług i usług działających w tle.

Nasza implementacja rejestrowania: helpers/logger.js

Wdrażamy kompleksową redagowanie pól w celu ochrony poufnych informacji, jednocześnie utrzymując przydatne możliwości debugowania w naszym środowisku produkcyjnym Node.js.

Monitorowanie specyficzne dla aplikacji

Nasze implementacje serwerowe:

Monitorowanie kolejki: Wprowadzamy limity kolejek 5 GB i 180-sekundowe limity czasu dla przetwarzania żądań, aby zapobiec wyczerpaniu zasobów. Te wzorce dotyczą dowolnej aplikacji Node.js z kolejkami lub przetwarzaniem w tle.

Monitorowanie produkcji Node.js za pomocą kontroli kondycji PM2

Udoskonaliliśmy konfigurację naszego środowiska produkcyjnego Node.js za pomocą PM2 na przestrzeni lat doświadczenia produkcyjnego. Nasze kontrole kondycji PM2 są niezbędne do utrzymania niezawodności w dowolnej aplikacji Node.js.

Nasz system kontroli stanu PM2

Nasza główna implementacja: jobs/check-pm2.js

Nasze monitorowanie produkcji Node.js z kontrolą stanu PM2 obejmuje:

  • Kursuje co 20 minut poprzez harmonogram cron
  • Wymaga minimalnego czasu sprawności wynoszącego 15 minut zanim uznasz proces za zdrowy
  • Sprawdza stan procesu i wykorzystanie pamięci
  • Automatycznie uruchamia ponownie nieudane procesy
  • Zapobiega pętlom ponownego uruchamiania poprzez inteligentną kontrolę stanu zdrowia

[!CAUTION] W przypadku najlepszych praktyk wdrażania produkcyjnego Node.js wymagamy 15+ minut czasu sprawności przed uznaniem procesu za zdrowy, aby uniknąć pętli restartu. Zapobiega to kaskadowym awariom, gdy procesy mają problemy z pamięcią lub innymi problemami.

Nasza konfiguracja produkcyjna PM2

Konfiguracja naszego ekosystemu: Zapoznaj się z naszymi plikami startowymi serwera dotyczącymi konfiguracji środowiska produkcyjnego Node.js:

Wzorce te mają zastosowanie niezależnie od tego, czy uruchamiasz aplikacje Express, serwery Koa, interfejsy API GraphQL czy dowolną inną aplikację Node.js.

Automatyczne wdrażanie PM2

Wdrażanie PM2: ansible/playbooks/node.yml

Całą konfigurację PM2 zautomatyzowaliśmy za pomocą Ansible, aby zapewnić spójność wdrożeń produkcyjnych Node.js na wszystkich naszych serwerach.

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

Jedną z naszych najważniejszych dobrych praktyk wdrażania Node.js w środowisku produkcyjnym jest inteligentna klasyfikacja błędów, która ma zastosowanie w każdej aplikacji Node.js:

Nasza implementacja isCodeBug dla produkcji

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

Ten pomocnik zapewnia inteligentną klasyfikację błędów dla aplikacji Node.js w środowisku produkcyjnym, co umożliwia:

  • Nadaj priorytet rzeczywistym błędom przez błędy użytkownika
  • Ulepsz naszą reakcję na incydenty skupiając się na prawdziwych problemach
  • Zmniejsz zmęczenie czujnością z oczekiwanych błędów użytkownika
  • Lepiej zrozumieć problemy aplikacyjne i generowane przez użytkownika

Ten wzorzec sprawdza się w przypadku dowolnej aplikacji Node.js — niezależnie od tego, czy tworzysz witryny e-commerce, platformy SaaS, interfejsy API czy mikrousługi.

Integracja z naszym rejestrowaniem produkcji

Integracja naszego rejestratora: helpers/logger.js

Nasz rejestrator używa isCodeBug aby określić poziomy alertów i redagowanie pól, dzięki czemu będziemy otrzymywać powiadomienia o rzeczywistych problemach, jednocześnie filtrując szum 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 profilowania do analizowania migawek sterty i debugowania problemów OOM (Out of Memory), wąskich gardeł wydajności i 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 migawek sterty i profili procesora
  • cpupro - Do analizowania profili procesora i migawek sterty

[!TIP] Używamy v8-profiler-next i cpupro razem, aby utworzyć kompletny przepływ pracy debugowania wydajności dla naszych aplikacji Node.js. Ta kombinacja pomaga nam identyfikować wycieki pamięci, wąskie gardła wydajności i optymalizować nasz kod produkcyjny.

Jak wdrażamy analizę migawek sterty

Nasza implementacja monitoringu: helpers/monitor-server.js

Nasze monitorowanie produkcji obejmuje automatyczne generowanie migawek sterty, gdy progi pamięci zostaną przekroczone. Pomaga nam to debugować problemy z OOM, zanim spowodują awarie aplikacji.

Kluczowe wzorce wdrażania:

  • Automatyczne migawki gdy rozmiar sterty przekroczy próg 2 GB
  • Profilowanie oparte na sygnałach do analizy na żądanie w produkcji
  • Zasady przechowywania do zarządzania pamięcią masową migawek
  • Integracja z naszymi pracami porządkowymi do automatycznej konserwacji

Przepływ pracy debugowania wydajności

Zapoznaj się z naszą rzeczywistą realizacją:

W przypadku analizy migawki sterty:

  1. Zainstaluj v8-profiler-next do generowania migawek
  2. Użyj cpupro do analizy wygenerowanych migawek
  3. Wdrożenie progów monitorowania podobnie do naszego monitor-server.js
  4. Skonfiguruj automatyczne czyszczenie aby zarządzać pamięcią masową migawek
  5. Utwórz obsługę sygnałów do profilowania na żądanie w produkcji

Do profilowania procesora:

  1. Generuj profile procesora w okresach dużego obciążenia
  2. Analizuj za pomocą cpupro identyfikować wąskie gardła
  3. Skup się na gorących ścieżkach i możliwości optymalizacji
  4. Monitoruj przed/po poprawa wydajności

[!WARNING] Generowanie migawek sterty i profili procesora może mieć wpływ na wydajność. Zalecamy wdrożenie dławienia i włączanie profilowania tylko podczas badania konkretnych problemów lub w trakcie okien konserwacyjnych.

Integracja z naszym monitorowaniem produkcji

Nasze narzędzia profilowania integrują się z naszą szerszą strategią monitorowania:

  • Automatyczne wyzwalanie na podstawie progów pamięci/procesora
  • Integracja alertów gdy zostaną wykryte problemy z wydajnością
  • Analiza historyczna aby śledzić trendy wydajności w czasie
  • Korelacja z metrykami aplikacji do kompleksowego debugowania

Dzięki takiemu podejściu udało nam się zidentyfikować i rozwiązać problemy z wyciekami pamięci, zoptymalizować ścieżki często występującego kodu i 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 poprzez automatyzację Ansible. Te praktyki dotyczą dowolnej 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:

  • Zamiana wyłączona aby zapobiec zapisaniu poufnych danych na dysku
  • Zrzuty rdzenia wyłączone aby zapobiec zrzutom pamięci zawierającym poufne informacje
  • Zablokowano pamięć USB aby zapobiec nieautoryzowanemu dostępowi do danych
  • Strojenie parametrów jądra zarówno pod kątem bezpieczeństwa, jak i wydajności

[!WARNING] Podczas wdrażania najlepszych praktyk wdrażania produkcyjnego Node.js wyłączenie swapu może spowodować zabójstwa z powodu braku pamięci, jeśli Twoja aplikacja przekroczy dostępną pamięć RAM. Dokładnie monitorujemy wykorzystanie pamięci i odpowiednio dobieramy rozmiary naszych serwerów.

Bezpieczeństwo aplikacji dla aplikacji Node.js

Nasza redakcja pola dziennika: helpers/logger.js

Redagujemy wrażliwe pola z dzienników, w tym hasła, tokeny, klucze API i dane osobowe. Chroni to prywatność użytkownika, jednocześnie utrzymując możliwości debugowania w dowolnym środowisku produkcyjnym Node.js.

Automatyzacja bezpieczeństwa infrastruktury

Nasza kompletna konfiguracja Ansible dla środowiska produkcyjnego Node.js:

Nasza treść dotycząca bezpieczeństwa

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

Architektura bazy danych dla aplikacji Node.js

Używamy hybrydowego podejścia bazodanowego zoptymalizowanego dla naszych aplikacji Node.js. Te wzorce można dostosować do dowolnej aplikacji Node.js:

Implementacja SQLite dla produkcji Node.js

Z czego korzystamy:

Nasza konfiguracja: ansible/playbooks/sqlite.yml

W naszych aplikacjach Node.js do obsługi danych specyficznych dla użytkownika używamy SQLite, ponieważ zapewnia ono:

  • Izolacja danych na użytkownika/najemcę
  • Lepsza wydajność dla zapytań pojedynczego użytkownika
  • Uproszczone tworzenie kopii zapasowych i migracja
  • Zredukowana złożoność w porównaniu do współdzielonych baz danych

Ten wzorzec sprawdza się w przypadku aplikacji SaaS, systemów wielodostępnych i dowolnych aplikacji Node.js wymagających izolacji danych.

Implementacja MongoDB dla środowiska produkcyjnego Node.js

Z czego korzystamy:

Nasza implementacja konfiguracji: helpers/setup-mongoose.js

Nasza konfiguracja: config/mongoose.js

W naszym środowisku produkcyjnym Node.js do obsługi danych aplikacji używamy MongoDB, ponieważ zapewnia ono:

  • Elastyczny schemat do rozwijania struktur danych
  • Lepsza wydajność do złożonych zapytań
  • Skalowanie poziome możliwości
  • Bogaty język zapytań

[!NOTE] Nasze hybrydowe podejście optymalizuje nasz konkretny przypadek użycia. Przeanalizuj nasze rzeczywiste wzorce wykorzystania bazy danych w bazie kodu, aby zrozumieć, czy to podejście pasuje do potrzeb Twojej aplikacji Node.js.

Tło produkcyjne Node.js Przetwarzanie zadań

Zbudowaliśmy naszą architekturę zadań w tle wokół Bree, aby zapewnić niezawodne wdrożenie produkcyjne Node.js. Dotyczy to każdej aplikacji Node.js, która wymaga przetwarzania w tle:

Nasza konfiguracja serwera Bree do produkcji

Nasza główna realizacja: bree.js

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

Przykłady pracy produkcyjnej

Monitorowanie stanu zdrowia: jobs/check-pm2.js

Automatyzacja czyszczenia: jobs/cleanup-tmp.js

Wszystkie nasze prace: Przeglądaj nasz kompletny katalog ofert pracy

Wzorce te mają zastosowanie do dowolnej aplikacji Node.js, która wymaga:

  • Zadania zaplanowane (przetwarzanie danych, raporty, czyszczenie)
  • Przetwarzanie w tle (zmiana rozmiaru obrazu, wysyłanie wiadomości e-mail, importowanie danych)
  • Monitorowanie i utrzymanie zdrowia
  • Wykorzystanie wątku roboczego w przypadku zadań intensywnie wykorzystujących procesor

Nasze wzorce harmonogramowania zadań dla produkcji Node.js

Zapoznaj się z naszymi aktualnymi schematami planowania pracy w naszym katalogu ofert pracy, aby zrozumieć:

  • Jak wdrażamy harmonogramowanie podobne do cron w produkcji Node.js
  • Nasza logika obsługi błędów i ponawiania prób
  • Jak wykorzystujemy wątki robocze do zadań intensywnie wykorzystujących procesor

Automatyczna konserwacja aplikacji produkcyjnych Node.js

Wdrażamy proaktywną konserwację, aby zapobiec typowym problemom produkcyjnym Node.js. Te wzorce dotyczą dowolnej aplikacji Node.js:

Nasza implementacja oczyszczania

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

Nasze zautomatyzowane usługi konserwacji aplikacji produkcyjnych Node.js mają na celu:

  • Pliki tymczasowe starsze niż 24 godziny
  • Pliki dziennika poza limitami retencji
  • Pliki pamięci podręcznej i dane tymczasowe
  • Przesłane pliki które nie są już potrzebne
  • Migawki sterty z debugowania wydajności

Wzorce te mają zastosowanie do dowolnej aplikacji Node.js, która generuje pliki tymczasowe, dzienniki lub dane w pamięci podręcznej.

Zarządzanie przestrzenią dyskową dla produkcji Node.js

Nasze progi monitorowania: helpers/monitor-server.js

  • Limity kolejki do przetwarzania w tle
  • 75% wykorzystania dysku próg ostrzegawczy
  • Automatyczne czyszczenie gdy przekroczone zostaną progi

Automatyzacja konserwacji infrastruktury

Nasza automatyzacja Ansible dla produkcji Node.js:

Przewodnik wdrażania produkcji Node.js

Zapoznaj się z naszym aktualnym kodem, aby poznać najlepsze praktyki produkcyjne

Aby skonfigurować środowisko produkcyjne Node.js, zacznij od następujących plików kluczowych:

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

Ucz się z naszych wpisów na blogu

Nasze przewodniki po implementacji technicznej dla środowiska produkcyjnego Node.js:

Automatyzacja infrastruktury dla produkcji Node.js

Nasze podręczniki Ansible do nauki wdrażania Node.js w środowisku produkcyjnym:

Nasze studia przypadków

Nasze wdrożenia korporacyjne:

Wnioski: najlepsze praktyki wdrażania Node.js w środowisku produkcyjnym

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

  • Sprawdzone wybory sprzętowe (AMD Ryzen dla 573% optymalizacji wydajności pojedynczego rdzenia)
  • Sprawdzony w boju monitoring produkcji Node.js z określonymi progami i automatycznymi odpowiedziami
  • Inteligentna klasyfikacja błędów w celu usprawnienia reagowania na incydenty w środowiskach produkcyjnych
  • Zaawansowane debugowanie wydajności z v8-profiler-next i cpupro w celu zapobiegania OOM
  • Kompleksowe wzmocnienie bezpieczeństwa poprzez automatyzację Ansible
  • Hybrydowa architektura bazy danych zoptymalizowany pod kątem potrzeb aplikacji
  • Automatyczna konserwacja aby zapobiec typowym problemom produkcyjnym Node.js

Najważniejsze wnioski: Zapoznaj się z naszymi rzeczywistymi plikami implementacyjnymi i wpisami na blogu, zamiast stosować się do ogólnych najlepszych praktyk. Nasza baza kodu dostarcza wzorców ze świata rzeczywistego dla wdrożeń produkcyjnych Node.js, które można dostosować do dowolnej aplikacji Node.js — aplikacji internetowych, interfejsów API, mikrousług lub usług w tle.

Pełna lista zasobów dla produkcji Node.js

Nasze podstawowe pliki wdrożeniowe

Nasze wdrożenia serwerowe

Nasza Infrastruktura Automatyzacja

Nasze posty na blogu technicznym

Nasze studia przypadków przedsiębiorstw