sysadmin.ecommerce > devops-log-274-log-274-log-274-log-274-zero-downtime-deployment-w.md
root@prod-01:~/blog# cat devops-log-274-log-274-log-274-log-274-zero-downtime-deployment-w.md
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Data: 2025-09-05 | Kategoria: Skalowanie & DevOps | Czas czytania: 7 min
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Zero-Downtime Deployment w e-commerce: Dlaczego symlinki gubią ścieżki i jak bezpiecznie odświeżać OPcache pod silnym ruchem

###02

01 Diagnoza z terminala: Anatomia cichej awarii

W profesjonalnych potokach wdrożeniowych standardem jest, że deweloperzy testują i zatwierdzają kod na środowisku stagingowym, a automatyczny pipeline CI/CD przenosi zweryfikowaną paczkę na produkcję. Aby uniknąć przerw w działaniu sklepu, stosuje się wtedy technologię Atomic Deployment (wdrożenie atomowe). Narzędzia takie jak Deployer czy Capistrano budują nową wersję aplikacji w odizolowanym katalogu (releases/20260625_v2), a w finalnym kroku podmieniają dowiązanie symboliczne wskazujące na katalog główny:

bash

ln -sfn /var/www/sklep/releases/20260625_v2 /var/www/sklep/current

Dla serwera Nginx zmiana jest natychmiastowa. Jednak w środowisku e-commerce pod silnym ruchem produkcyjnym, ta jedna milisekunda podmiany symlinka potrafi wygenerować na żywym organizmie falę błędów 502 Bad Gateway500 Internal Server Error, „białych stron” (Fatal Error) lub nagły skok utylizacji CPU do 100%.

Winowajcą nie jest sam kod ze stagingu, ale sposób, w jaki PHP-FPM oraz OPcache traktują ścieżki systemowe i i-węzły (inodes) pod dużym obciążeniem.

02 Mechanika problemu: Gdzie ukrywa się błąd?

Gdy serwer obsługuje setki żądań na sekundę, jądro Linuksa oraz silnik PHP optymalizują zapytania do dysku, wprowadzając dwa niezależne mechanizmy keszowania ścieżek i kodu. To one stają się pułapką podczas atomowego wdrożenia.

Realpath Cache – keszowanie ścieżek fizycznych

PHP nie odpytuje systemu operacyjnego o lokalizację pliku przy każdym wywołaniu include czy require – byłoby to zabójstwem dla wydajności I/O. Wyniki translacji ścieżek są zapisywane w pamięci podręcznej procesu jako realpath_cache.

Gdy podmieniasz symlink current, aktywne, długożyjące procesy PHP-FPM (zwłaszcza te w trybie pm = static) nadal pamiętają starą ścieżkę fizyczną z realpath_cache. W efekcie część procesów zaczyna wykonywać kod z nowego wydania, a część próbuje ładować pliki pomocnicze ze starego (lub już usuniętego) katalogu release. Skutkuje to natychmiastowym wymieszaniem stanów aplikacji i błędami typu Class not found.

OPcache i indeksacja po symlinkach

OPcache przechowuje prekompilowany kod bajtowy w pamięci RAM, indeksując go po pełnej ścieżce pliku. Jeśli konfiguracja opiera się na uniwersalnej ścieżce symlinku (np. /var/www/sklep/current/index.php), OPcache po automatycznej zmianie dowiązania może uznać, że plik fizycznie się nie zmienił, ponieważ jego ścieżka wejściowa pozostała taka sama. W skrajnych przypadkach serwuje stary kod bajtowy, ignorując nowe wydanie.

03 Rozwiązanie krok po kroku: Konfiguracja stosu LEMP pod Atomic Deployment

Krok 1: Optymalizacja php.ini pod zaawansowany e-commerce (PHP 8.x)

Aby wyeliminować błędy przesunięcia i-węzłów oraz odpowiednio przygotować silnik PHP do obsługi tysięcy plików (charakterystycznych dla Magento, PrestaShop czy rozbudowanego WooCommerce), dostosuj parametry OPcache i pamięci podręcznej ścieżek w pliku /etc/php/8.3/fpm/php.ini:

ini

; Włącz sprawdzanie zmian w plikach na podstawie znaczników czasu
opcache.validate_timestamps = 1
opcache.revalidate_freq = 0

; Zabezpieczenie przed kompilacją niekompletnych plików w trakcie operacji I/O
opcache.file_update_protection = 2

; Rozwiązanie problemów z duplikatami ścieżek w strukturach symlinków
opcache.dups_fix = 1

; Zwiększenie limitu kluczy w pamięci współdzielonej – domyślne 4000 to za mało
opcache.max_accelerated_files = 100000

; Optymalizacja Realpath Cache pod częste zmiany katalogów wydań
realpath_cache_size = 4096k
realpath_cache_ttl = 600

💡 Wskazówka dotycząca realpath_cache_ttl: Wartość 600 sekund stanowi optymalny kompromis wydajnościowy. Zapobiega ciągłym odpytywaniom o strukturę katalogów (VFS) przy każdym żądaniu HTTP, oszczędzając operacje I/O, jednocześnie na tyle szybko odświeżając cache, by zminimalizować okno błędu po zmianie symlinka.

⚠️ Ważna uwaga dotycząca opcache.preload: Jeśli używasz mechanizmu Preloading (PHP 7.4+, częsta praktyka w aplikacjach Symfony/Magento), pamiętaj, że klasy załadowane przez opcache.preload są całkowicie odporne na czyszczenie w locie. W takim przypadku restart lub pełny reload PHP-FPM po wdrożeniu jest obowiązkowy.

Krok 2: Konfiguracja Nginx – przekazywanie ścieżki rzeczywistej

Bardzo częstym błędem w konfiguracji wirtualnego hosta jest przekazywanie do PHP-FPM zmiennej $document_root, która zawiera nierozwinięty symlink. Należy zmodyfikować plik konfiguracji witryny, aby przekazywał do backendu rzeczywistą, rozwiązaną ścieżkę fizyczną ($realpath_root):

nginx

# /etc/nginx/sites-available/sklep.conf

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    
    # Zamiast domyślnego $document_root:
    fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    fastcgi_param DOCUMENT_ROOT $realpath_root;
}

Po modyfikacji wykonaj: sudo nginx -t && sudo systemctl reload nginx.

Krok 3: Wdrożenie Cachetool i rozgrzewanie kodu przed przełączeniem ruchu

Najgorszym rozwiązaniem stosowanym w skryptach wdrożeniowych jest wymuszenie twardego restartu usługi (systemctl restart php8.3-fpm), co przerywa aktywne koszyki i sesje płatności klientów. Z kolei soft-reload (systemctl reload) czyści całą pamięć OPcache jednocześnie, wywołując zjawisko Cache Stampede – setki procesów PHP jednocześnie rzucają się do kompilacji nowych plików, co natychmiast winduje CPU do 100% i zamraża serwer.

Rozwiązaniem jest zastosowanie narzędzia Cachetool, które komunikuje się z PHP-FPM przez FastCGI, oraz wdrożenie strategii wyprzedzającej kompilacji cache.

Instalacja narzędzia na serwerze:

bash

curl -sLO https://gordalina.github.io/cachetool/downloads/cachetool.phar
chmod +x cachetool.phar
sudo mv cachetool.phar /usr/local/bin/cachetool

Procedura wdrożeniowa w skrypcie pipeline’u CI/CD:
Zamiast resetować OPcache po podmianie symlinka, zmień kolejność działań. Rozgrzej OPcache dla nowej wersji kodu, zanim użytkownicy w ogóle na nią trafią:

bash

# KROK A: Kod jest już w nowym katalogu, ale symlink 'current' JESZCZE wskazuje na starą wersję.
# Wymuszamy prewencyjną kompilację nowej paczki kodu w tle:
cachetool opcache:compile-scripts --fcgi=/run/php/php8.3-fpm.sock /var/www/sklep/releases/20260625_v2

# KROK B: Podmiana symlinka (atomowa operacja w systemie plików)
ln -sfn /var/www/sklep/releases/20260625_v2 /var/www/sklep/current

# KROK C: Celowany reset struktur Realpath oraz OPcache bez dotykania demonów systemowych
cachetool opcache:reset --fcgi=/run/php/php8.3-fpm.sock

Dzięki temu nowe żądania klientów od razu trafiają na skompilowany wcześniej w pamięci RAM kod, eliminując opóźnienia pierwszego uruchomienia i chroniąc procesor przed przeciążeniem.

Krok 4: Weryfikacja powdrożeniowa

Po zakończeniu pipeline’u upewnij się, że struktura pamięci podręcznej odzwierciedla stan faktyczny:

bash

# Sprawdzenie statusu i statystyk OPcache
cachetool opcache:status --fcgi=/run/php/php8.3-fpm.sock

# Sprawdzenie aktualnego stanu i rozmiaru realpath_cache
cachetool stat:realpath --fcgi=/run/php/php8.3-fpm.sock

04 Alternatywa dla skrajnie wymagających: Blue-Green Deployment

Jeśli Twój sklep e-commerce generuje obroty rzędu milionów euro, a jakakolwiek operacja na poziomie symlinków systemu plików niesie za sobą ryzyko, standardem architektonicznym staje się Blue-Green Deployment.

W tym modelu rezygnujemy z podmiany symlinków na jednym serwerze. Infrastruktura składa się z dwóch identycznych, niezależnych środowisk produkcyjnych: Blue (aktywna wersja) oraz Green (nowe wydanie przetransportowane ze stagingu). Wdrożenie polega na pełnym uruchomieniu i wygrzaniu środowiska Green w całkowitej izolacji, a następnie natychmiastowym przełączeniu ruchu użytkowników na poziomie Load Balancera (HAProxy, Nginx Plus, AWS ALB). W przypadku wykrycia anomalii, rollback polega jedynie na ponownym przekierowaniu ruchu na instancję Blue – bez ryzyka uszkodzenia plików czy wyczyszczenia pamięci podręcznej kodu.

05 Podsumowanie i checklist dla DevOps

Aby automatyczne potoki deploymentu były w 100% bezpieczne dla żywego organizmu produkcyjnego, zweryfikuj poniższe punkty kontrolne:

  • Nginx: SCRIPT_FILENAME zaimplementowane jako $realpath_root.
  • PHP.ini: Włączona dyrektywa opcache.dups_fix = 1 oraz podniesiony opcache.max_accelerated_files.
  • Realpath Cache: realpath_cache_ttl ustawione na wartość nie dłuższą niż 600 sekund.
  • CI/CD Pipeline: Wdrożone rozgrzewanie kodu poleceniem opcache:compile-scripts przed fizyczną zmianą dowiązania symbolicznego.
  • Bezpieczeństwo operacyjne: Całkowity zakaz stosowania systemctl restart php-fpm w automatycznych skryptach produkcyjnych. Zastąpiony celowanym resetem OPcache przez FastCGI.
  • Monitoring: Skonfigurowany alert na nagły spadek trafień w OPcache (hit rate) po wdrożeniu.

← Powrot do wszystkich artykulow

// alert_systemowy

Widzisz podobne symptomy na swoim serwerze e-commerce? Nie czekaj na awarię w szczycie ruchu.

→ Przejdź do formularza i zgłoś serwer do audytu zerowego