,

Chyba 524 na WooCommerce: proč e-shop padal každou půlhodinu

E-shop na WooCommerce s přibližně 10 000 produkty měl všechno, co se pro rychlý a stabilní web obvykle doporučuje: vlastní dedikovaný server, nasazenou cache a před sebou Cloudflare. Přesto byl každou půlhodinu nedostupný. Návštěvníci dostávali chybu 524, a když se web zrovna načetl, načítal se…

E-shop na WooCommerce s přibližně 10 000 produkty měl všechno, co se pro rychlý a stabilní web obvykle doporučuje: vlastní dedikovaný server, nasazenou cache a před sebou Cloudflare.

Přesto byl každou půlhodinu nedostupný. Návštěvníci dostávali chybu 524, a když se web zrovna načetl, načítal se pomalu. V analytice se to projevilo vysokou mírou okamžitého opuštění.

Na začátku jsme vůbec nedokázali přijít na to, proč. Na papíře bylo všechno v pořádku a nikde nebyla chyba, na kterou by šlo ukázat. První dvě kola oprav nepomohla.

Výchozí situace

E-shop běží na WordPressu a WooCommerce, má přibližně 10 000 produktů a tři jazykové domény. Je na dedikovaném serveru, o který se dělí jen s jedním dalším e-shopem. Ten má asi 1 000 produktů a minimální zátěž, takže vysvětlení, že výkon ujídá soused, odpadlo hned. Web měl nasazenou cache a provoz šel přes Cloudflare.

Výpadky přicházely každou půlhodinu, bez ohledu na návštěvnost. Zákazník v tu chvíli viděl chybovou stránku Cloudflare 524. Ta znamená, že Cloudflare se k serveru připojil, ale nedočkal se od něj včas odpovědi. Web byl nedostupný i několik minut. Majitel, který se chtěl podívat do administrace, dostal z wp-adminu chybu 503, takže ani on neviděl, co se na serveru děje.

Mezi výpadky se web načítal pomalu. Obojí dohromady bylo vidět v analytice na vysoké míře okamžitého opuštění: lidé přišli, nedočkali se stránky a odešli.

Pravidelnost výpadků byla první vodítko. Kdyby server nestíhal nápor zákazníků, padal by ve špičce. Tenhle padal i ve chvílích, kdy na webu skoro nikdo nebyl.

Vyšetřování: od symptomu k datům

Cesta k příčině nebyla přímá. Nejdřív jsme opravovali to, co se nabízelo, a výpadky se pokaždé vrátily. Teprve potom jsme přestali hledat pomalý kód a začali sledovat, co se děje se serverem.

Access logy: kdo na web chodí

První pohled patřil access logům. Byly plné user-agentů AI a SEO botů, což samo o sobě není nic zvláštního. Zvláštní bylo, o co žádali: opakovaně chtěli soubory, které na webu už neexistovaly, například gtm4wp/dist/js/….

Podezření na boty se nabízelo, a tak jsme po nich šli jako první.

První pokus: blokování botů v Cloudflare

V logu byly i požadavky botů na URL s parametrem add_to_cart. Takovou adresu cache neobslouží, každá jde do PHP a spouští WooCommerce. V Cloudflare jsme proto zablokovali všechny požadavky botů na URL s add_to_cart.

Nestačilo to, takže jsme přitvrdili a zablokovali všechny neschválené boty.

Situace se zlepšila, ale jen na chvíli. Do 24 hodin bylo všechno zpět a web padal stejně jako předtím.

Druhý pokus: pomalé pluginy

Pokud to nebyli jen boti, musel být problém v aplikaci. Nasadili jsme New Relic pro profilování a hledali úzká hrdla, od procesů jádra WooCommerce po jednotlivé pluginy.

Pluginy, které se nepoužívaly vůbec nebo jen minimálně a šly odstranit, jsme odebrali. Jako výrazná zátěž se ukázal plugin pro filtrování produktů (WooCommerce Product Filter), který poměrně významně zatěžoval archiv produktů. Nahradili jsme ho vlastním řešením s pokročilým cache indexem.

Ani to nepomohlo. Výpadky pokračovaly.

PHP-FPM pool: co se děje se serverem

Po dvou neúspěšných kolech jsme změnili směr. Dalším krokem bylo živé sledování PHP-FPM poolu, tedy procesů, které vyřizují požadavky na PHP. Nechali jsme si průběžně vypisovat jednotlivé workery s jejich pamětí (RSS) a zatížením CPU.

Tady se poprvé ukázalo něco konkrétního. Workery nerostly o megabajty, ale na gigabajty, a nic je nezastavilo. Věděli jsme tedy, že serveru dochází paměť. Nevěděli jsme, co ji spotřebovává.

New Relic: které požadavky paměť žerou

New Relic jsme už měli nasazený. Tentokrát jsme se v něm ale ptali jinak: ne co je pomalé, ale co spotřebovává paměť.

Dali jsme vedle sebe dvě sady dat. Paměť jednotlivých procesů (ProcessSample) a transakce z APM, tedy přehled toho, jaké URL server v danou chvíli vyřizoval. Z jejich korelace bylo vidět, které URL paměť spotřebovávají.

Graf paměti workerů měl pilovitý průběh. Paměť rostla až k 13–18 GB, pak spadla a začala růst znovu.

Slowlog: co přesně PHP dělá

Poslední krok byl PHP slowlog, který u pomalých požadavků zapisuje, ve které funkci PHP právě je. Stack trace ukázal konkrétní místo, a nebyl to košík ani pokladna. Bylo to vykreslování stránky 404, kde čas trávily Block Hooks a wp_kses.

Nejdražší operací na celém e-shopu tak byla odpověď „tahle stránka neexistuje“.

Kořenová příčina: řetězec, ne jedna chyba

Když jsme nálezy složili za sebe, vyšel řetězec šesti článků. Žádný z nich by sám web neshodil.

  1. AI a SEO boti. Crawlují masivně a bez ohledu na cache. Na webu, kde je všechno ostatní v pořádku, je to jen zvýšený provoz.
  2. Update pluginu. Plugin při aktualizaci přesunul složku s JavaScriptem z dist/js do build. Pro návštěvníky se nic nezměnilo, stránky odkazovaly na nové umístění. Staré URL ale zůstaly v oběhu a boti se na ně ptali dál.
  3. Tisíce 404. Požadavky na zaniklé soubory nevyřídil webserver sám. Soubor na disku nenašel, a tak požadavek předal WordPressu, tedy do PHP.
  4. Drahá 404. WordPress kvůli každému takovému požadavku vykreslil celou stránku 404 se vším, co k ní patří: Block Hooks, sanitizace, překlady. Místo okamžité odpovědi na dotaz po jednom souboru .js tak pokaždé proběhl plný render.
  5. Limit 2 GB na request. Paměťový limit PHP byl nastavený vysoko, „ať je klid“. Jediný požadavek tak směl zabrat až 2 GB, než ho PHP ukončilo.
  6. Nefunkční pojistky. PHP-FPM má pro takové případy dvě pojistky a obě selhaly. Časový limit požadavku byl zapsaný jako php_admin_value[request_terminate_timeout], tedy na místě, kde neplatí, a PHP-FPM ho tiše ignorovalo. Recyklace workeru přicházela až po 500 požadavcích, což bylo příliš pozdě.

V praxi to vypadalo takto: boti poslali vlnu požadavků na staré soubory, každý z nich spustil drahý render stránky 404 a workery začaly růst. Limit je nezastavil, timeout neplatil a recyklace nepřišla včas. Paměť workerů vystoupala na 13–18 GB a Cloudflare vracel 524.

Bez botů by drahou 404 nikdo ve velkém nevolal. Bez updatu pluginu by boti dostávali existující soubory. S rozumným limitem a funkčním timeoutem by si server s vlnou 404 poradil.

Řešení ve třech vrstvách

Řetězec šlo přerušit na kterémkoli článku. Přerušili jsme ho na třech místech najednou, aby jedna selhaná vrstva neznamenala další výpadek. Všechno na straně Cloudflare se vešlo do plánu Free.

Edge (Cloudflare)

První vrstva má zachytit co nejvíc požadavků dřív, než vůbec dorazí na server.

  • Cache everything pro anonymní HTML. Nepřihlášený návštěvník dostane stránku z edge cache Cloudflare a server se o požadavku nedozví.
  • Redirect pravidla na přesunuté soubory. Kdo se zeptá na starou URL, je přesměrován na nové umístění souboru.
  • Challenge pro boty na drahých URL. Vlastní pravidlo s Managed Challenge stojí před adresami, jejichž vyřízení je pro server nákladné.

Server

Druhá vrstva řeší to, co přes Cloudflare projde.

  • Okamžitá 404 pro neexistující statické soubory. Pravidlo v .htaccess vrátí 404 rovnou z webserveru. PHP ani WordPress se kvůli chybějícímu souboru nespustí.
  • Funkční pojistky workerů. Časový limit je zapsaný jako direktiva poolu, kde skutečně platí. Worker se recykluje po 50 požadavcích místo po 500.
  • Slowlog. Zůstal zapnutý, aby příští pomalý požadavek bylo vidět hned.

Aplikace

Třetí vrstva zlevňuje požadavky, které do WordPressu oprávněně dojdou.

  • Reálné paměťové limity. Limit odpovídá tomu, co požadavek skutečně potřebuje, ne 2 GB.
  • Vypnutí drahého hooku. Hook, který prodražoval vykreslování, vypíná krátký mu-plugin.
  • Redis object cache. Opakované dotazy do databáze se vyřizují z paměti.

Výsledky

Výpadky skončily. Paměť workerů, která dřív rostla bez omezení až k 18 GB, se drží pod stropem kolem 4 GB. Vyhledávání, které předtím končilo timeoutem, odpovídá za 0,24 s.

MetrikaPředPo
Paměť PHP workerů13–18 GB, neomezený růststrop ~4 GB
Odezva na zaniklé souboryplný PHP render, desítky sekund pod zátěžíokamžitá 404 bez PHP
Vyhledávánítimeouty0,24 s
Výpadky 524každou půlhodinu0
Recyklace workerupo 500 requestechpo 50 requestech
Anonymní HTMLvždy PHPz edge cache

Checklist: co zkontrolovat na vlastním webu

  • Po updatu pluginu ověřte, jestli staré URL jeho souborů nežijí dál v cache nebo v externích odkazech.
  • 404 nesmí být drahá. Neexistující statický soubor nemá budit PHP.
  • Paměťový limit PHP je pojistka, ne polštář. Vyšší hodnota neznamená lepší.
  • Pojistky PHP-FPM otestujte, že opravdu zabírají. Direktiva na špatném místě nedělá nic a nikde to nehlásí.
  • Boti si vaše nejdražší URL najdou sami. Počítejte s tím v cache i ve WAF.
  • Jedna příčina web neshodí, řetězec ano. Hledejte celý řetězec.

Padá vám web a hosting říká, že je všechno v pořádku?

Ozvěte se. Projdeme logy a konfiguraci serveru a najdeme, kde se řetězec skládá.