Twój WooCommerce też muli?Optymalizacja WooCommerce
← Blog
WooCommerce

Wolny WooCommerce mimo cache: 5 przyczyn, które znaleźliśmy w sklepach klientów

Czas odpowiedzi z 1,5 s do 0,1 s bez zmiany hostingu. Pięć przyczyn wolnego WooCommerce, które znaleźliśmy w sklepach klientów, i jak je sprawdzić u siebie.

WooCommerce najczęściej działa wolno mimo WP Rocket, bo sklep ustawia ciasteczko każdemu gościowi, a strony z nagłówkiem Set-Cookie nie trafiają do cache. Zwykle winna jest sesja PHP uruchamiana przez motyw albo wtyczkę. W tym tekście opisujemy pięć przyczyn wolnego sklepu, które znaleźliśmy u klientów: ciasteczka, OPcache, przeciążony serwer, ciężkie zapytania i hosting. Przy każdej podajemy liczby przed i po naprawie.

Jak sprawdzić, czy cache w WooCommerce w ogóle działa?

Objaw w jednym ze sklepów: WP Rocket aktywny od miesięcy, a czas odpowiedzi serwera (TTFB) na każdej stronie 1300–1600 ms. Katalog cache był pusty. Wtyczka nie zgłaszała żadnego błędu, po prostu niczego nie zapisywała.

Sprawdzisz to w minutę. Wyślij zapytanie jako niezalogowany gość i obejrzyj nagłówki:

curl -sI https://example.com/ | grep -iE 'set-cookie|x-cache|cf-cache-status'
  • Jeśli widzisz Set-Cookie: PHPSESSID=..., sklep startuje sesję PHP dla każdego gościa. To blokuje cache.
  • Każde inne ciasteczko ustawiane gościowi przy pierwszym wejściu też jest podejrzane.
  • Zajrzyj do wp-content/cache/wp-rocket/. Pusty katalog po kilku godzinach ruchu oznacza, że cache nie działa.

Przyczyna 1: dlaczego sesja PHP wyłącza cache WP Rocket?

Motyw wywoływał session_start() bezwarunkowo, na hooku init z priorytetem 1, więc każda strona dostawała ciasteczko PHPSESSID, a WP Rocket nie zapisywał żadnej z nich. Ani jednej. Drugi bloker znaleźliśmy we wtyczce płatności, która ustawiała własne ciasteczko każdemu nowemu gościowi.

Tu jest pułapka. Wcześniej ktoś próbował obejść problem w nginx dyrektywą fastcgi_ignore_headers Set-Cookie. Efekt: serwer cache'ował odpowiedź razem z ciasteczkiem i różni użytkownicy dostawali ten sam PHPSESSID, czyli współdzielili sesję. Dlatego kolejność naprawy jest ważna: najpierw usuwasz sesję, dopiero potem zdejmujesz to obejście.

Masz ten sam problem? Widzisz Set-Cookie dla niezalogowanego gościa? Sprawdzimy, która wtyczka je ustawia i jak się jej pozbyć bez psucia sklepu. Opisz sytuację →

Co zmieniliśmy:

  1. Sesja startuje dopiero wtedy, gdy kod faktycznie coś do niej zapisuje (lazy session).
  2. Moduł „ostatnio oglądane” przeszedł z sesji PHP na ciasteczko i AJAX.
  3. Mały mu-plugin neutralizuje ciasteczka, których gość nie potrzebuje.
  4. W PixelYourSite wyłączyliśmy sesję.
  5. Wygenerowaliśmy od nowa przeterminowany config WP Rocket. Stary miał zapisany permalink bez końcowego ukośnika, więc pomijał cache dla każdego adresu.
PomiarPrzedPo
TTFB realnego użytkownika przez Cloudflare1300–1600 ms41–107 ms
Origin, trafienie w cachebrak cache7 ms

Po nagrzaniu cache strona główna odpowiada w 31 ms, produkty w 32–55 ms. Zimne strony, jeszcze nie zapisane w cache, nadal ładują się 1,5–2,1 s. Ten sam wzorzec znaleźliśmy w drugim sklepie: session_start() na init i wtyczka do pobierania danych z GUS skutecznie wyłączały page cache.

Przyczyna 2: czy OPcache może spowolnić albo położyć sklep?

OPcache przyspiesza PHP, ale źle ustawiony daje dwa rodzaje kłopotów.

Stary kod po wdrożeniu. Przy opcache.validate_timestamps=0 PHP nie sprawdza, czy pliki się zmieniły. Po wdrożeniu trzeba przeładować PHP-FPM (sygnał USR2 albo restart). Polecenie wp eval 'opcache_reset();' czyści OPcache procesu CLI, a nie FPM. Z kolei revalidate_freq=240 kosztowało nas 2–3 fałszywe diagnozy typu „poprawka nie działa”, bo PHP sprawdzał zmiany w plikach najwyżej co 4 minuty.

Uszkodzona pamięć OPcache. Cały sklep zwracał błąd 500, a w logu był taki wpis z pliku motywu:

Allowed memory size of ... bytes exhausted (tried to allocate 4295229440 bytes) in .../theme.php

Nikt nie alokuje 4 GB w szablonie. Przyczyną był za mały OPcache (bufor interned strings zapełniony w 100%) w połączeniu z JIT w trybie tracing na PHP 8.4. Na PHP 8.3 ten sam tryb JIT powodował SIGSEGV procesów php-fpm. Ustawienia, które to rozwiązały:

opcache.memory_consumption=512
opcache.interned_strings_buffer=64
opcache.jit=off

Przyczyna 3: co mają procesy zombie do wolnego sklepu?

Czasem winny jest serwer, nie WordPress. Na wspólnym VPS działało około 15 projektów, w tym sklepy WooCommerce, a jedna z aplikacji używała Puppeteera, czyli przeglądarki Chrome sterowanej z Node.js w kontenerze Docker. Po godzinie na serwerze było 2971 procesów zombie, około 500 na kontener. W kontenerze PID 1 to był node, który nie zbiera zakończonych procesów potomnych Chrome.

Naprawa to jedna linia w docker-compose: init: true. Docker uruchamia wtedy tini jako PID 1 i liczba zombie spadła do zera. Osobny problem stanowiła nielimitowana równoległość tej samej aplikacji: 2,5 GB zajętej pamięci, OOM, swap i load 40–60. A na tym samym serwerze stały sklepy klientów. Jeśli load rośnie bez widocznego powodu, sprawdź też, czy to nie koparka kryptowalut w kontenerze.

Przyczyna 4: ciężkie zapytania i „zombie cache”

W kolejnym sklepie WP Rocket był wyłączony, ale w wp-content został jego plik advanced-cache.php. Ten dropin dalej serwował HTML sprzed 9 dni.

Ten sam sklep miał zapytanie z meta_query łączącym OR i NOT EXISTS na tabeli postmeta z 1,36 mln wierszy. Jedno wykonanie trwało 10–16 s. Po naprawie listing produktów spadł z 2–8 s do 1,2–2,8 s, a strony dla gości z 85–120 ms do 65–85 ms.

Takie zapytania znajdziesz wtyczką Query Monitor (lista zapytań z czasem i miejscem wywołania) albo w slow query logu MySQL. Jeśli nie używasz żadnej wtyczki cache, a plik advanced-cache.php istnieje, to też jest sygnał do sprawdzenia.

Przyczyna 5: czy zmiana hostingu przyspieszy WooCommerce?

Częściowo. Po migracji jednego sklepu z hostingu współdzielonego na nowy serwer zmierzyliśmy:

StronaHosting współdzielonyNowy serwer
Koszyk2,09–2,64 s1,06–1,42 s
Strona główna (zimna)4,6–6,8 s2,1–2,3 s
Produkt (zimny)2,6–8,2 s1,30–1,32 s
Strona z cache (ciepła)ok. 0,07 sok. 0,07 s

Strony z cache były szybkie już wcześniej. Lepszy hosting pomaga tam, gdzie cache nie sięga, czyli w koszyku i na checkoucie, a jeśli cache w ogóle nie działa przez ciasteczko, sama migracja tego nie naprawi i każde wejście dalej będzie liczone przez PHP od zera.

W jednym z audytów pomogło zajrzenie w statystyki bazy. Redis jako object cache miał 98,3% trafień, bufor InnoDB 99,98%, ale 27% tabel tymczasowych lądowało na dysku. Podnieśliśmy tmp_table_size z 16 do 64 MB.

Od czego zacząć diagnozę wolnego sklepu?

  1. Sprawdź nagłówki curl -I jako gość: Set-Cookie, x-cache, cf-cache-status.
  2. Zajrzyj do katalogu cache.
  3. Upewnij się, że skrypt wdrożenia przeładowuje PHP-FPM, bo reset OPcache z poziomu WP-CLI nie dotyka procesów, które obsługują ruch.
  4. Przejrzyj log błędów PHP: dziwne alokacje pamięci, SIGSEGV.
  5. Sprawdź load i liczbę procesów, zwłaszcza na serwerze współdzielonym z innymi projektami.
  6. Włącz Query Monitor i slow query log na listingach produktów.

Kolejna wtyczka do cache nie pomogłaby w żadnym z tych przypadków. Dlatego w ASAPDevs zaczynamy optymalizację WooCommerce od pomiaru, a nie od instalowania kolejnej wtyczki.

Dokumentacja: ustawienia OPcache (php.net), session_start() (php.net), opcja init w Docker Compose.

Kamil Perzowski
Kamil Perzowski
CEO i co-founder ASAPDevs. Programuje i utrzymuje sklepy, aplikacje webowe i serwery klientów. LinkedIn · Optymalizacja WooCommerce
Masz ten sam problem?

Twój WooCommerce też muli?

Kamil Perzowski, ASAPDevs
Kamil Perzowski
CEO & Co-founder, ASAPDevs
Mierzymy, gdzie sklep traci czas, naprawiamy cache, PHP i bazę danych, a na koniec pokazujemy liczby przed i po. Pilne? Zadzwoń: +48 884 220 764.

Wysyłając formularz, przekazujesz nam dane, żebyśmy mogli odpowiedzieć. Szczegóły w polityce prywatności.

FAQ

Pytania i odpowiedzi

Czy WP Rocket działa z WooCommerce?

+
Tak. Koszyk, zamówienie i Moje konto są z cache wyłączone automatycznie, reszta stron dla gości trafia do cache. Warunek: strona nie może wysyłać gościowi ciasteczka, bo wtedy WP Rocket jej nie zapisze.

Dlaczego koszyk i checkout są wolne, skoro strona główna ładuje się szybko?

+
Bo tych stron nie da się cache'ować, za każdym razem liczy je PHP i baza danych. Tu pomaga szybszy serwer: po migracji z hostingu współdzielonego koszyk spadł u nas z 2,09–2,64 s do 1,06–1,42 s.

Czy mogę kazać nginx ignorować Set-Cookie, żeby cache zaczął działać?

+
Nie, dopóki sklep ustawia ciasteczko sesji. Serwer zapisze stronę razem z ciasteczkiem i rozda je kolejnym gościom. Widzieliśmy, jak różni użytkownicy dostawali ten sam PHPSESSID.

Czy opcache_reset() w WP-CLI czyści cache po wdrożeniu?

+
Nie. WP-CLI działa w osobnym procesie PHP CLI, który ma własną pamięć OPcache. Żeby PHP-FPM zobaczył nowy kod, przeładuj go sygnałem USR2 albo zrestartuj usługę.

Ile trwa nagrzanie cache po wyczyszczeniu?

+
Zależy od liczby adresów i szybkości serwera. W jednym sklepie warmup 212 URL zajmował około 130 sekund. Do tego czasu pierwsze wejście na stronę jest zimne, u nas 1,5–2,1 s.

Przeczytaj też