Porozmawiajmy o Twojej firmie

Node.js 27 alpha: co zmiany w V8 15.6, OpenSSL 4.1 i limitach pamięci oznaczają dla utrzymania aplikacji

Node.js 27 alpha: co zmiany w V8 15.6, OpenSSL 4.1 i limitach pamięci oznaczają dla utrzymania aplikacji

Node.js 27.0.0-alpha.0.0.0 ukazał się 29 października 2026 roku. To pierwsza publiczna próba nowej linii major, przygotowana przez Rafaela Gonzagę, z silnikiem V8 15.6.75.13 (w Node.js 26 było 14.6) i OpenSSL 4.1.0. Wpis na blogu projektu wymienia kilkadziesiąt zmian oznaczonych jako semver-major — od domyślnych limitów pamięci, przez nowy format serializacji, po usunięcie wbudowanego providera FIPS i zakończenie wsparcia engine’ów OpenSSL. Wersja jest oznaczona jako Alpha, więc nie jest przeznaczona do produkcji, ale lista zmian jest już na tyle konkretna, że pozwala zaplanować audyt zależności i testy regresji.

Zmiany dotyczą przede wszystkim zespołów utrzymujących aplikacje serwerowe w Node.js: backendów HTTP, usług kryptograficznych, procesów roboczych i kontenerów z ograniczoną pamięcią. Dlaczego to ważne teraz, a nie za pół roku? Bo część zmian działa w sposób cichy. Nowe domyślne limity sterty i wliczanie Buffer oraz ArrayBuffer do limitu heapu mogą zmienić zachowanie aplikacji bez żadnego błędu w logach. Nowy format serializacji potrafi zablokować komunikację między procesami działającymi na różnych wersjach Node.js w tym samym klastrze. A wymóg OpenSSL 3+ i koniec z engine’ami dotyka starszych integracji kryptograficznych, które często są ukryte w zależnościach firm trzecich. Wczesne wykrycie tych punktów jest tańsze niż reagowanie na nie po wdrożeniu.

Co dokładnie zmienia Node.js 27 alpha

Wpis wydawniczy grupuje zmiany w kilka obszarów. Poniżej rozdzielam to, co źródło stwierdza wprost, od tego, co z tego wynika dla typowej aplikacji. Pełny changelog V8 między 14.6 a 15.6 ma zostać opublikowany później — do tego czasu część obserwowalnych różnic w zachowaniu silnika pozostaje opisana tylko skrótowo.

V8 15.6: nowe funkcje języka i zmiany obserwowalne

Domyślnie włączone nowe funkcje to Math.sumPrecise(), Intl.Locale.prototype.variants, Iterator.prototype.join(), Iterator.prototype.includes(), Iterator.zip() i Iterator.zipKeyed(). Za flagami pozostają: import defer (–js-defer-import-eval), Immutable ArrayBuffer (–js-immutable-arraybuffer) i RegExp buffer boundaries (–js-regexp-buffer-boundaries).

Ważniejsza od nowości jest lista zmian w zachowaniu, które mogą ujawnić się w testach regresji:

  • metody Math korzystają teraz z libm z LLVM i mogą różnić się w ostatnim bicie wyniku;
  • sekwencje Math.random() zmieniają się dla danego –random-seed;
  • error.stack nie jest już wyszukiwany przez łańcuch prototypów;
  • await generuje mniej mikrozadań;
  • Array.prototype.sort() używa PowerSort dla dużych tablic i pozostaje stabilne;
  • asm.js nie jest już kompilowany do WebAssembly, a flagi –experimental-wasm-<name> przemianowano na –wasm-<name>.

Do tego dochodzą zmiany w diagnostyce: snapshoty sterty zawierają obiekty wewnętrzne, wartości liczbowe i pełne źródła skryptów. Ich tworzenie trwa około dwa razy dłużej, a plik jest około dwa razy większy. Dla zespołów analizujących wycieki pamięci to zmiana w jakości danych, ale też w koszcie ich zebrania.

Pamięć: nowy domyślny limit i wliczanie buforów

Gdy –max-old-space-size nie jest ustawione, domyślny limit sterty wynosi teraz połowę pamięci fizycznej, ograniczoną do przedziału 256 MB–4 GB. Dodatkowo pamięć zajmowana przez Buffer i ArrayBuffer wlicza się do limitu sterty. Źródło wprost zaleca, by aplikacje, które polegały na poprzednich domyślnych wartościach, ustawiały –max-old-space-size jawnie.

To jedna z tych zmian, które najłatwiej przeoczyć. Kontener z limitem 2 GB pamięci, który wcześniej działał „jakoś”, po aktualizacji może zacząć traktować duże bufory jako część heapu i szybciej dochodzić do progu. Nie oznacza to automatycznie awarii — próg jest teraz inaczej liczony, a nie niższy w każdym scenariuszu. Ale każdy serwis przetwarzający duże pliki, strumienie binarnych danych albo obrazy powinien sprawdzić, jak zachowuje się przy nowych domyślnych wartościach.

Serializacja: nowy format i cache kompilacji

v8.serialize(), structuredClone() i postMessage() używają nowego formatu, którego starsze wersje Node.js nie odczytają. v8.cachedDataVersionTag() i cache kompilacji zmieniają się przy każdym patchu V8 w Node.js, nie tylko przy zmianie wersji V8.

Konsekwencja jest praktyczna: w klastrze, w którym procesy nadrzędne i robocze działają na różnych wersjach Node.js, przesyłanie danych przez postMessage() lub odczyt wcześniej zapisanego cache kompilacji może się nie udać. To nie jest błąd do naprawienia w locie — to niezgodność formatu. Migracja musi więc obejmować cały klaster jednocześnie albo przejściowy okres z jawną konwersją danych.

Kryptografia: OpenSSL 4.1.0, koniec FIPS i engine’ów

Źródło podaje, że wymagany jest OpenSSL 3 lub nowszy, a źródła OpenSSL zaktualizowano do openssl-4.1.0. Usunięto wbudowany build providera FIPS. Zakończono wsparcie engine’ów OpenSSL w modułach crypto, https i tls. Deprecacje DEP0093, DEP0198, DEP0203 i DEP0204 przeniesiono do End-of-Life. Dodatkowo: Hmac.digest() wywołane więcej niż raz jest teraz runtime-deprecated, a Cipher/Decipher update oraz kodowanie wejścia i wyjścia digestu są walidowane. Wywołanie computeSecret na niezainicjalizowanym obiekcie DH kończy się błędem, a Web Crypto odrzuca resizable backing stores w parametrach buforów.

Dla firm z wymogami zgodności to najcięższy fragment wydania. Wbudowany FIPS znika — jeśli organizacja opierała się na nim, potrzebny będzie zewnętrzny provider FIPS albo inna ścieżka zgodności. Engine’y OpenSSL, używane historycznie do sprzętowych akceleratorów i modułów HSM, tracą wsparcie w tych modułach. To zmiana architektoniczna, nie kosmetyczna.

HTTP, sieć i pozostałe zmiany

W module http odpowiedzi przekraczające limit nagłówków są odrzucane, tworzenie bez new jest runtime-deprecated, a domyślny keepAliveTimeout wzrasta do 65 sekund. req.headers ma teraz prototyp null. W http2 zwiększono domyślne rozmiary okien. W net wywołanie listen więcej niż raz kończy się błędem, a autoselekcja rodziny adresów jest wyścigowa. W dns reverse lookupi nie konsultują już pliku hosts, a w dgram pomijany jest custom lookup dla literalnych adresów IP.

Moduł domain jest runtime-deprecated i przeniesiony na AsyncLocalStorage. W fs pojawia się natywna implementacja glob, a mkdtemp zwraca Buffer, gdy prefix jest Bufferem. npm zaktualizowano do 12.1.0. Wsparcie Intel macOS zdegradowano do eksperymentalnego. Pojawia się też flaga –allow-env w modelu uprawnień.

Realne konsekwencje dla firmowych aplikacji

Największe ryzyko nie leży w nowych funkcjach języka, tylko w zmianach, które nie generują błędów kompilacji. Poniższa tabela porządkuje obszary według tego, jak szybko mogą ujawnić się w produkcji.

Obszar Co się zmienia Typowy objaw Pilność
Pamięć Nowy domyślny limit sterty, bufory wliczane do heapu Wcześniejsze OOM, inne zużycie RSS Wysoka
Serializacja Nowy format v8.serialize, structuredClone, postMessage Błędy odczytu między wersjami w klastrze Wysoka przy mieszanych wersjach
Kryptografia OpenSSL 3+, brak FIPS, brak engine’ów Błędy inicjalizacji, utrata zgodności Wysoka przy zgodności
HTTP Limit nagłówków, keepAliveTimeout 65 s, req.headers bez prototypu Zerwane połączenia, błędy w kodzie sprawdzającym prototyp Średnia
Matematyka i losowość libm LLVM, inne sekwencje Math.random() Różnice w testach snapshotowych, inne wyniki symulacji Średnia
Diagnostyka Większe snapshoty sterty Dłuższe zrzuty, większe pliki Niska

Interpretacja: najpilniejsze są te zmiany, które działają bezgłośnie. Zmiana w Math czy sort() ujawni się w testach. Zmiana limitu pamięci może ujawnić się dopiero pod obciążeniem. Zmiana formatu serializacji może ujawnić się tylko wtedy, gdy w klastrze faktycznie mieszają się wersje — a to warto sprawdzić zawczasu.

Scenariusze ryzyka

Scenariusz 1: cichy wzrost zużycia pamięci

Usługa przetwarza duże pliki i trzyma je w Bufferach. Wcześniej bufory nie liczyły się do limitu sterty, więc proces działał stabilnie przy ustawieniach domyślnych. Po aktualizacji bufory wchodzą do limitu, a nowy domyślny limit zależy od pamięci fizycznej hosta. W kontenerze z limitem cgroup pamięć „fizyczna” widziana przez proces może być inna niż limit kontenera. Efekt: próg OOM pojawia się w innym miejscu niż wcześniej. To nie musi być błąd — ale musi być zmierzone.

Scenariusz 2: klaster z mieszanymi wersjami

Proces nadrzędny aktualizowany etapami, procesy robocze na starszej wersji. Jeśli komunikacja opiera się na postMessage() lub współdzielonym cache kompilacji, nowy format może być nieczytelny dla starszej strony. Objaw: błędy deserializacji przy starcie lub w trakcie pracy, trudne do przypisania do konkretnej zmiany.

Scenariusz 3: zgodność kryptograficzna

Organizacja opierała się na wbudowanym FIPS providerze albo na engine’ach OpenSSL do obsługi HSM. Po aktualizacji obie ścieżki znikają. To nie jest problem wydajnościowy — to problem zgodności i architektury. Wymaga decyzji przed migracją, nie po niej.

Scenariusz 4: zależności ukryte

Większość firm nie używa domain bezpośrednio, ale może go używać biblioteka w drzewie zależności. Podobnie z Hmac.digest() wywoływanym wielokrotnie albo z kodem sprawdzającym prototyp req.headers. To klasyczne ryzyko migracji: problem nie jest w kodzie pierwszej strony, tylko w zależnościach pośrednich.

Jak sprawdzić, czy problem dotyczy Twojej aplikacji

Poniższe czynności można wykonać bez wdrażania wersji alpha na produkcję. Wystarczy środowisko testowe i chwila na przegląd kodu.

  1. Sprawdź, czy ustawiasz –max-old-space-size jawnie. Jeśli nie, ustal, ile pamięci fizycznej widzi proces w Twoim środowisku (host, kontener, cgroup) i porównaj z obecnym zużyciem.
  2. Znajdź miejsca, w których trzymasz duże bufory. Przetwarzanie plików, strumienie binarne, obrazy, archiwa — wszystko, co alokuje Buffer lub ArrayBuffer.
  3. Sprawdź, czy w klastrze mieszają się wersje Node.js. Procesy nadrzędne, robocze, kontenery w różnych środowiskach — jeśli tak, ustal, czy przesyłają dane przez postMessage() lub współdzielą cache kompilacji.
  4. Przejrzyj użycie kryptografii. Szukaj engine’ów OpenSSL, konfiguracji FIPS, wywołań Hmac.digest() w pętlach, niestandardowych kodowań w Cipher/Decipher.
  5. Przeszukaj zależności pod kątem domain. Zarówno bezpośrednio, jak i w drzewie zależności.
  6. Sprawdź kod sprawdzający prototyp req.headers. Po zmianie obiekt ma prototyp null.
  7. Uruchom testy regresji na wersji alpha w izolowanym środowisku. Porównaj wyniki z obecną wersją, zwłaszcza w testach snapshotowych i symulacjach.

Plan reakcji krok po kroku

Krok 1: inwentaryzacja

Zbierz listę usług, ich wersje Node.js, ustawienia pamięci, zależności kryptograficzne i sposób komunikacji między procesami. Bez tego każda migracja będzie zgadywaniem.

Krok 2: testy w izolacji

Uruchom aplikację na Node.js 27 alpha w środowisku odzwierciedlającym produkcję: te same limity pamięci, ten sam sposób uruchamiania, te same zależności. Zmierz zużycie pamięci, czas startu i wyniki testów.

Krok 3: analiza różnic

Porównaj wyniki z obecną wersją. Zwróć uwagę na testy snapshotowe (zmiany w Math i Math.random()), testy sortowania, testy serializacji i testy kryptograficzne. Różnice w ostatnim bicie wyników matematycznych nie muszą być błędem — ale muszą być świadomą decyzją.

Krok 4: decyzja o zakresie migracji

Ustal, które zmiany wymagają refaktoryzacji przed migracją, a które można zaakceptować. Zmiany w domain, engine’ach OpenSSL i formacie serializacji zwykle wymagają pracy. Zmiany w diagnostyce i nowe funkcje języka można przyjąć bez przygotowania.

Krok 5: migracja etapowa

Nie migruj całego klastra jednocześnie, jeśli komunikacja między procesami zależy od formatu serializacji. Zaplanuj okres przejściowy albo migrację całościową z krótkim oknem. To decyzja architektoniczna, nie operacyjna.

Typowe błędy przy migracji

  • Traktowanie wersji alpha jak stabilnej. Alpha nie jest przeznaczona do produkcji. Może zawierać błędy, które zostaną naprawione przed wydaniem stabilnym.
  • Pomijanie domyślnych limitów pamięci. Zespół zakłada, że „skoro wcześniej działało, to nadal będzie działać”. Nie będzie — limit jest liczony inaczej.
  • Testowanie tylko na jednej wersji Node.js. Klaster z mieszanymi wersjami to najczęstsze źródło problemów z serializacją.
  • Ignorowanie zależności pośrednich. domain i Hmac.digest() często siedzą w bibliotekach, nie w kodzie pierwszej strony.
  • Odkładanie decyzji o FIPS na później. To nie jest problem do rozwiązania w dniu wdrożenia.
  • Brak pomiaru zużycia pamięci przed i po. Bez pomiaru nie da się odróżnić regresji od normalnej zmienności.

Działania krótkoterminowe

W ciągu najbliższych tygodni warto zrobić trzy rzeczy. Po pierwsze, ustawić jawnie –max-old-space-size w środowiskach produkcyjnych — to niezależne od migracji i zmniejsza niepewność. Po drugie, zinwentaryzować użycie kryptografii i domain w zależnościach. Po trzecie, uruchomić testy regresji na wersji alpha w izolowanym środowisku, żeby poznać skalę różnic.

Działania długoterminowe

W perspektywie kilku miesięcy warto zaplanować refaktoryzację kodu korzystającego z domain na AsyncLocalStorage, przegląd integracji kryptograficznych pod kątem OpenSSL 3+ i przygotowanie planu zastępczego dla FIPS. Warto też ustalić politykę migracji klastrów: czy migrujemy całościowo, czy etapowo z okresem przejściowym. To decyzje, które powinny zapaść przed wydaniem stabilnym, nie po nim.

Praktyczna checklista

  • ☐ Sprawdź, czy –max-old-space-size jest ustawione jawnie.
  • ☐ Zmierz zużycie pamięci przed i po aktualizacji w środowisku testowym.
  • ☐ Zidentyfikuj miejsca alokujące duże Buffer i ArrayBuffer.
  • ☐ Sprawdź, czy w klastrze mieszają się wersje Node.js.
  • ☐ Przejrzyj użycie postMessage() i cache kompilacji.
  • ☐ Zinwentaryzuj engine’y OpenSSL i konfigurację FIPS.
  • ☐ Przeszukaj zależności pod kątem domain.
  • ☐ Sprawdź kod sprawdzający prototyp req.headers.
  • ☐ Uruchom testy regresji na wersji alpha.
  • ☐ Porównaj wyniki testów snapshotowych i symulacji.
  • ☐ Zaplanuj migrację klastra z uwzględnieniem formatu serializacji.
  • ☐ Ustal plan zastępczy dla FIPS, jeśli dotyczy.

Co powinien zrobić właściciel firmy / administrator

Właściciel firmy: nie traktuj tej wersji jako gotowej do wdrożenia. Alpha służy do testów i planowania. Zapytaj zespół techniczny o trzy rzeczy: czy mamy jawnie ustawione limity pamięci, czy nasze integracje kryptograficzne przetrwają koniec z FIPS i engine’ami, oraz czy nasz klaster wytrzyma migrację bez mieszania wersji. Odpowiedzi na te pytania są ważniejsze niż data wydania stabilnej wersji.

Administrator: zabezpiecz środowiska produkcyjne przed przypadkową aktualizacją do wersji alpha — przypnij wersje w menedżerze pakietów i w obrazach kontenerów. W środowisku testowym uruchom aplikację na Node.js 27 alpha z tymi samymi limitami pamięci co produkcja. Zbierz metryki zużycia pamięci, czasu startu i błędów. Udokumentuj różnice i przekaż zespołowi deweloperskiemu. Nie wdrażaj zmian w kryptografii bez konsultacji z zespołem odpowiedzialnym za zgodność.

Wersja 27.0.0-alpha.0.0.0 jest oznaczona jako Alpha. Wszystkie opisane zmiany pochodzą z wpisu wydawniczego projektu Node.js. Pełny changelog V8 między 14.6 a 15.6 nie został jeszcze opublikowany, więc część obserwowalnych różnic w zachowaniu silnika może zostać doprecyzowana przed wydaniem stabilnym.

Weryfikacja praktyczna przed wdrożeniem

Weryfikacja nie polega na jednorazowym uruchomieniu testów. Chodzi o powtarzalny proces, który daje porównywalne wyniki między obecną wersją Node.js a wersją 27.0.0-alpha.0.0.0. Poniżej sekcje, które warto przejść po kolei — każda kończy się konkretnym artefaktem, który zostaje w dokumentacji zespołu.

Etap 1: odtworzenie środowiska produkcyjnego w izolacji

Środowisko testowe musi odzwierciedlać produkcję w czterech wymiarach: limity pamięci, sposób uruchamiania procesu, zestaw zależności i topologia procesów. Jeśli produkcja działa w kontenerze z ograniczeniem cgroup, środowisko testowe musi mieć takie samo ograniczenie — inaczej pomiar domyślnego limitu sterty (połowa pamięci fizycznej, clamp między 256 MB a 4 GB) da fałszywy obraz.

  • Zapisz dokładną komendę startową z produkcji, wraz z flagami — w szczególności sprawdź, czy --max-old-space-size jest ustawione jawnie, czy nie.
  • Zapisz wersję Node.js w każdym kontenerze i na każdym hoście, na których działa aplikacja.
  • Zapisz wersję npm — w wersji 27 alpha jest to npm 12.1.0, więc różnica względem produkcji może wpłynąć na instalację zależności.
  • Zapisz konfigurację kryptografii: czy używany jest FIPS provider, czy jakikolwiek OpenSSL engine, jaka wersja OpenSSL jest wymagana.
  • Zapisz, czy procesy komunikują się przez postMessage() i czy współdzielą cache kompilacji.

Artefakt etapu: plik konfiguracyjny środowiska testowego, który można odtworzyć jedną komendą. Bez tego każdy kolejny pomiar jest nieporównywalny.

Etap 2: pomiar bazowy na obecnej wersji

Zanim uruchomisz wersję alpha, zmierz obecną wersję. To punkt odniesienia — bez niego różnice w pamięci i czasie startu będą interpretowane dowolnie.

  1. Uruchom aplikację trzy razy i zmierz czas startu do momentu gotowości do przyjmowania ruchu.
  2. Zmierz zużycie pamięci po ustabilizowaniu: RSS, heap used, heap total, external, arrayBuffers.
  3. Uruchom pełny zestaw testów i zapisz wyniki, w tym testy snapshotowe.
  4. Zapisz czas wykonania testów — zmiany w silniku V8 mogą wpłynąć na wydajność.
  5. Zapisz rozmiar i czas tworzenia heap snapshotu, jeśli go używasz w diagnostyce.

Artefakt etapu: raport bazowy z liczbami, nie z opisami. „Działało szybko” nie jest pomiarem.

Etap 3: pomiar na wersji alpha

Powtórz dokładnie te same czynności na Node.js 27 alpha, w tym samym środowisku, z tymi samymi danymi wejściowymi. Kluczowa różnica: pamięć zajmowana przez Buffer i ArrayBuffer liczy się teraz do limitu sterty. Aplikacje przetwarzające duże pliki, strumienie binarne, obrazy lub archiwa mogą zobaczyć zupełnie inny profil pamięci niż wcześniej.

  • Porównaj czas startu — różnica może wynikać z nowego formatu serializacji lub zmian w V8.
  • Porównaj zużycie pamięci z rozbiciem na heap i external — wzrost w external przy stabilnym heap oznacza, że bufory wchodzą do limitu.
  • Porównaj wyniki testów snapshotowych — zmiany w Math (libm LLVM) i Math.random() (sekwencje dla danego --random-seed) mogą powodować różnice w ostatnim bicie lub w kolejności wartości.
  • Porównaj testy sortowania — Array.prototype.sort() używa PowerSort dla dużych tablic, pozostaje stabilne, ale wydajność może się różnić.
  • Porównaj testy serializacji — v8.serialize(), structuredClone() i postMessage() używają nowego formatu, którego starsze wersje nie odczytają.
  • Porównaj czas i rozmiar heap snapshotu — według materiału źródłowego jest około dwukrotnie dłuższy i około dwukrotnie większy, bo zawiera obiekty wewnętrzne, wartości liczbowe i pełne źródła skryptów.

Artefakt etapu: raport różnic z jawnym wskazaniem, które różnice są oczekiwane, a które wymagają decyzji.

Etap 4: weryfikacja kryptografii

Kryptografia wymaga osobnej ścieżki weryfikacji, bo zmiany są nieodwracalne w skutkach. W wersji 27 usunięto wbudowany build FIPS provider, usunięto legacy OpenSSL code paths, zakończono wsparcie dla OpenSSL engine, a Node.js wymaga OpenSSL 3 lub nowszego. Dodatkowo deprecacje DEP0093, DEP0198, DEP0203 i DEP0204 przeszły do End-of-Life, a Hmac.digest() wywoływane więcej niż raz jest runtime-deprecate.

  1. Wypisz wszystkie miejsca, w których konfiguracja FIPS jest wymagana — nie tylko w kodzie, ale w wymaganiach zgodności.
  2. Wypisz wszystkie integracje z HSM i innymi urządzeniami, które działają przez OpenSSL engine.
  3. Przeszukaj kod pod kątem wielokrotnych wywołań Hmac.digest() na tym samym obiekcie.
  4. Sprawdź walidację kodowań wejściowych i wyjściowych w Cipher/Decipher — wersja 27 waliduje inputEncoding i encoding wyjściowy digestu.
  5. Sprawdź, czy Web Crypto otrzymuje resizable backing stores w parametrach bufora — są odrzucane.
  6. Sprawdź, czy kod wywołuje computeSecret na niezainicjalizowanym obiekcie DH — teraz rzuca błąd.

Artefakt etapu: decyzja architektoniczna dotycząca FIPS i engine’ów, podjęta przed migracją. To nie jest problem do rozwiązania w dniu wdrożenia.

Etap 5: weryfikacja zależności pośrednich

Największe ryzyko migracji siedzi w drzewie zależności. Moduł domain jest runtime-deprecate i przeniesiony na AsyncLocalStorage — ale kod pierwszej strony rzadko go używa bezpośrednio. Podobnie z kodem sprawdzającym prototyp req.headers: po zmianie obiekt ma prototyp null, a error.stack nie jest już wyszukiwany przez łańcuch prototypów.

  • Przeszukaj całe drzewo zależności, nie tylko bezpośrednie zależności, pod kątem domain.
  • Przeszukaj kod pod kątem odwołań do prototypu req.headers i error.stack.
  • Sprawdź, czy jakakolwiek zależność polega na starym formacie serializacji — na przykład przez postMessage() lub współdzielony cache kompilacji.
  • Sprawdź, czy zależności wywołują http bez new — jest to runtime-deprecate.
  • Sprawdź, czy zależności polegają na domyślnym keepAliveTimeout — wzrósł do 65 sekund.
  • Sprawdź, czy zależności polegają na tym, że asm.js jest kompilowany do WebAssembly — już nie jest.

Artefakt etapu: lista zależności wymagających aktualizacji lub refaktoryzacji, z przypisanym właścicielem.

Monitoring po wdrożeniu

Monitoring po wdrożeniu musi być zaprojektowany przed wdrożeniem. Wersja alpha nie jest przeznaczona do produkcji, więc monitoring dotyczy środowiska testowego i etapów migracji — ale metryki powinny być te same, które zbierasz na produkcji, żeby porównanie było możliwe.

Metryki obowiązkowe

  • Zużycie pamięci z rozbiciem: RSS, heap used, heap total, external, arrayBuffers. Rozbicie jest krytyczne, bo bufory wchodzą teraz do limitu sterty.
  • Liczba restartów procesu z powodem — wzrost restartów po migracji może wskazywać na przekroczenie limitu sterty.
  • Czas startu do momentu gotowości — porównanie z bazą.
  • Liczba błędów deserializacji — sygnał problemów z nowym formatem serializacji.
  • Liczba błędów kryptograficznych z rozbiciem na typ: walidacja kodowania, niezainicjalizowany DH, resizable backing store, wielokrotne Hmac.digest().
  • Ostrzeżenia deprecacji — domain, http bez new, Hmac.digest().
  • Czas i rozmiar heap snapshotów, jeśli są tworzone automatycznie — według materiału źródłowego około dwukrotnie dłuższe i większe.

Progi alarmowe

Progi należy ustalić na podstawie pomiaru bazowego, nie na podstawie odczuć. Przykładowe podejście: alarm, gdy zużycie pamięci przekracza wartość bazową o więcej niż 20% przez więcej niż 10 minut; alarm, gdy liczba błędów deserializacji jest większa od zera; alarm, gdy pojawia się jakiekolwiek ostrzeżenie deprecacji dotyczące domain lub kryptografii.

Monitoring klastra z mieszanymi wersjami

Jeśli migracja jest etapowa, monitoring musi rozróżniać wersje Node.js w procesach. Metryki agregowane na poziomie klastra maskują problemy — błąd deserializacji w jednym procesie roboczym na starszej wersji może wyglądać jak sporadyczny błąd w całym klastrze.

  • Oznacz każdą metrykę wersją Node.js procesu, który ją wygenerował.
  • Monitoruj komunikację między procesami: liczba wiadomości, liczba błędów, opóźnienie.
  • Monitoruj cache kompilacji: trafienia, chybienia, błędy odczytu.
  • Ustal okno przejściowe i monitoruj, czy wszystkie procesy przeszły na nową wersję w zaplanowanym czasie.

Monitoring zmian w zachowaniu silnika

Zmiany w V8 mogą być niewidoczne w metrykach infrastrukturalnych, ale widoczne w logice aplikacji. Monitoring powinien obejmować testy ciągłe, które wykrywają różnice w wynikach matematycznych, sortowaniu i serializacji.

  • Uruchamiaj testy snapshotowe w trybie ciągłym i porównuj wyniki między wersjami.
  • Monitoruj wyniki Math w miejscach, gdzie precyzja ma znaczenie — metody używają teraz libm LLVM i mogą różnić się w ostatnim bicie.
  • Monitoruj sekwencje Math.random() w testach, które zakładają konkretny --random-seed.
  • Monitoruj liczbę mikrozadań w ścieżkach z await — jest ich mniej, co może zmienić kolejność operacji w testach współbieżności.

Checklisty operacyjne

Checklista przed uruchomieniem testów na wersji alpha

  1. ☐ Środowisko testowe odzwierciedla limity pamięci produkcji (host, kontener, cgroup).
  2. ☐ Zapisana komenda startowa z produkcji, wraz z flagami.
  3. ☐ Zapisane wersje Node.js i npm we wszystkich środowiskach.
  4. ☐ Zapisana konfiguracja kryptografii: FIPS, OpenSSL engine, wersja OpenSSL.
  5. ☐ Zapisany sposób komunikacji między procesami: postMessage(), cache kompilacji.
  6. ☐ Wykonany pomiar bazowy na obecnej wersji: czas startu, pamięć, testy.
  7. ☐ Zapisany czas i rozmiar heap snapshotu na obecnej wersji.
  8. ☐ Zespół odpowiedzialny za zgodność poinformowany o usunięciu FIPS provider i engine’ów OpenSSL.

Checklista weryfikacji kodu przed migracją

  1. ☐ --max-old-space-size ustawione jawnie lub świadoma decyzja o pozostawieniu domyślnego limitu.
  2. ☐ Zidentyfikowane miejsca alokujące duże Buffer i ArrayBuffer.
  3. ☐ Przeszukane drzewo zależności pod kątem domain.
  4. ☐ Przeszukany kod pod kątem odwołań do prototypu req.headers.
  5. ☐ Przeszukany kod pod kątem odwołań do error.stack przez łańcuch prototypów.
  6. ☐ Przeszukany kod pod kątem wielokrotnych wywołań Hmac.digest().
  7. ☐ Sprawdzona walidacja kodowań w Cipher/Decipher i digestach.
  8. ☐ Sprawdzone użycie computeSecret na obiektach DH.
  9. ☐ Sprawdzone użycie Web Crypto z resizable backing stores.
  10. ☐ Sprawdzone użycie http bez new.
  11. ☐ Sprawdzone poleganie na domyślnym keepAliveTimeout.
  12. ☐ Sprawdzone poleganie na kompilacji asm.js do WebAssembly.
  13. ☐ Sprawdzone użycie flag --experimental-wasm-<name> — przemianowane na --wasm-<name>.
  14. ☐ Sprawdzone użycie fs.mkdtemp z prefiksem będącym Buffer — zwraca teraz Buffer.
  15. ☐ Sprawdzone użycie dns w reverse lookups — hosts file nie jest już konsultowany.
  16. ☐ Sprawdzone użycie dgram z literalnymi adresami IP — custom lookup jest pomijany.

Checklista przed migracją etapową klastra

  1. ☐ Ustalony format komunikacji między procesami i jego zależność od wersji Node.js.
  2. ☐ Ustalony sposób współdzielenia cache kompilacji i jego zależność od wersji Node.js.
  3. ☐ Zaplanowane okno przejściowe z jasnym kryterium zakończenia.
  4. ☐ Monitoring rozróżniający wersje Node.js w procesach.
  5. ☐ Plan wycofania na wypadek błędów deserializacji.
  6. ☐ Decyzja: migracja etapowa czy całościowa z krótkim oknem.
  7. ☐ Udokumentowane ryzyko: nowy format serializacji jest nieczytelny dla starszych wersji Node.js.

Checklista po wdrożeniu — pierwsze 24 godziny

  1. ☐ Porównane zużycie pamięci z bazą, z rozbiciem na heap i external.
  2. ☐ Porównany czas startu z bazą.
  3. ☐ Sprawdzona liczba restartów procesu i ich powody.
  4. ☐ Sprawdzona liczba błędów deserializacji — powinna być zero.
  5. ☐ Sprawdzone ostrzeżenia deprecacji — domain, http bez new, Hmac.digest().
  6. ☐ Sprawdzone błędy kryptograficzne z rozbiciem na typ.
  7. ☐ Sprawdzone wyniki testów snapshotowych w trybie ciągłym.</li

    Źródła i materiały do dalszej weryfikacji

    Artykuł jest autorskim opracowaniem przygotowanym na podstawie poniższych materiałów. Linki prowadzą do publikacji źródłowych.

    1. Node.js — Node.js 27.0.0-alpha.0.0.0 (Alpha) (nodejs.org)

    Zdjęcie wyróżniające: Bibek ghosh / Pexels.

Masz pytanie do tego tematu? Napisz do nas — odpowiemy konkretnie.

Porozmawiajmy

Potrzebujesz kogoś, kto ogarnie technologię w Twojej firmie?

Porozmawiajmy o tym, co możemy przejąć, usprawnić albo zbudować. Pierwsza rozmowa jest bezpłatna i do niczego nie zobowiązuje.