Sklep padł albo dysk jest prawie pełny?Opieka nad WordPressem
← Blog
Obsługa IT

Sklep WooCommerce offline przez pełny dysk: UpdraftPlus, Redis MISCONF i błąd 521

Strona główna odpowiada 200 z cache Cloudflare, a koszyk zwraca 521. Co zapycha dysk sklepu, dlaczego pada Redis, baza i proxy naraz oraz jak ustawić strażnika, który reaguje przed końcem miejsca.

Sklep WooCommerce, który zwraca błąd 521, a w logach ma MISCONF Redis is configured to save RDB snapshots, najczęściej ma pełny dysk. Winowajcą bywa backup UpdraftPlus pakowany na tym samym dysku co produkcja albo logi bez rotacji. Poniżej opisujemy, jak taka awaria wygląda od środka, dlaczego strona główna potrafi wtedy dalej odpowiadać 200 i jak ustawić zabezpieczenie, które reaguje, zanim miejsce się skończy, a nie po fakcie.

Jak wygląda pełny dysk w sklepie WooCommerce?

Objawy były zawsze podobne. Koszyk, wp-admin i wp-json zwracały 521 z Cloudflare, a po chwili klient widział komunikat o błędzie połączenia z bazą danych. Strona główna dalej otwierała się z kodem 200, więc zwykły monitoring uptime nie alarmował.

To pułapka. Cloudflare potrafi podać stronę główną z własnej pamięci podręcznej, także wtedy, gdy origin nie żyje, dopóki wpis w cache jest ważny albo włączone jest serwowanie nieaktualnej treści. Jeśli sprawdzasz sklep jednym adresem, widzisz zielone światło przy martwym zapleczu. Diagnozę zaczynamy od kontroli koszyka i adresu dynamicznego, na przykład wp-json, oraz od nagłówka CF-Cache-Status. Losowy parametr (?nc=1234) często omija cache, ale nie zawsze, bo Cloudflare może ignorować query string w kluczu.

Co zapycha dysk produkcyjnego sklepu?

Na dysku 150 GB, na którym stały sklepy i baza, miejsce znikało dwiema drogami.

Backup UpdraftPlus pakowany lokalnie

UpdraftPlus tworzy paczki najpierw w wp-content/updraft, dopiero potem wysyła je do zdalnego magazynu i kasuje lokalne pliki. Katalog uploadów miał 53 GB, a pełny zestaw zajmował zwykle od około 12 do 34 GB. Nieudane próby potrafiły dobić do 50 GB. Raz kopia pocięła uploady na 129 części po około 400 MB, razem około 50 GB. Innym razem wysyłanie do zdalnego magazynu urwało się w połowie. Na dysku zostały 262 pliki, 49,5 GB, i zajętość doszła do 145 z 150 GB.

Logi bez rotacji

Drugi scenariusz to logi. W jednym przypadku zjadły dysk cztery pliki:

  • debug log integratora magazynowego: 5,5 GB, bo logowanie debug zostało włączone i nikt go potem nie wyłączył,
  • log wtyczki eksportu: 1,9 GB powtarzanego komunikatu „Export is not triggered”,
  • log JSON kontenera z WordPressem: 1,5 GB, nakręcany błędami object cache,
  • access log serwera: 202 MB.

Błędy Redisa zwiększały log kontenera, a pełny log kontenera pogłębiał problem z miejscem. Pętla zamykała się sama.

Dlaczego pełny dysk wyłącza Redisa, bazę i cały serwer?

Przy pełnym dysku awarie szły kaskadą:

  1. Redis. Nie może zapisać migawki RDB, więc przy ustawieniu stop-writes-on-bgsave-error yes odrzuca wszystkie zapisy. W logach WordPressa widać MISCONF oraz Failed to execute SET/ZADD. Sklep działa, ale bez object cache.
  2. Kontenery. Trzy kontenery padły z kodem wyjścia 128, w tym kontener WordPressa, Redis i kontener drugiej strony stojącej na tym samym VPS-ie.
  3. Baza. Nocny restart MariaDB z crona trafił w moment pełnego dysku. Proces mysqld nie doszedł do stanu gotowości, a kontener wyglądał na działający, choć gniazdo było martwe.
  4. Proxy. Nginx Proxy Manager, wspólny dla wszystkich witryn na serwerze, po restarcie wpadł w pętlę z błędem [emerg] host not found in upstream, bo jeden z kontenerów stał zatrzymany. Bez proxy nie działał żaden sklep na tej maszynie, nie tylko ten z awarią.

Jak sprawdzić, które kontenery naprawdę działają?

Po awarii docker ps -a pokazywał „Up 33 hours” przy kontenerach, które dawno padły. Stan odczytujemy z inspekcji:

docker inspect --format '{{.Name}} {{.State.Status}} exit={{.State.ExitCode}}' $(docker ps -aq)

Kontener w stanie „running” z martwą bazą sprawdzamy połączeniem z poziomu aplikacji, a nie samym statusem.

Masz ten sam problem? Strona główna działa, ale koszyk zwraca 521? Sprawdzimy dysk, kontenery i bazę, przywrócimy sklep i ustawimy alerty. Opisz sytuację →

Jak przywrócić sklep po zapełnieniu dysku?

  1. Usuń przerwane paczki z wp-content/updraft, gdy backup się nie dokończył (zostają pliki tymczasowe bez końcowego archiwum) albo kompletna kopia leży w zdalnym magazynie. W ten sposób odzyskaliśmy 40 GB. Jeśli nie masz pewności, przenieś paczki na inny dysk zamiast je kasować.
  2. Uruchom zatrzymane kontenery (Redis, WordPress), potem zrestartuj proxy, a na końcu bazę.
  3. Sprawdź test konfiguracji nginx w proxy. Przechodzi dopiero wtedy, gdy wszystkie kontenery z konfiguracji istnieją.
  4. Zweryfikuj sklep z zewnątrz, z parametrem omijającym cache: strona główna, koszyk, wp-json, przez kilka prób.
  5. Dla Redisa sprawdź BGSAVE i rdb_last_bgsave_status:ok.

Potem sprzątamy to, co zajmuje miejsce na stałe: wyłączamy debug logi, dodajemy rotację, ograniczamy logi Dockera (max-size: 20m, max-file: 3) i usuwamy stare obrazy. W jednym przypadku obraz kontenera zajmował 23 GB, bo budowanie kopiowało do warstwy cały katalog z uploadami. Plik .dockerignore zmniejszył go do 960 MB.

Jak zabezpieczyć dysk, żeby to się nie powtórzyło?

Skrypt sprzątający raz na dobę nie wystarcza. Nasz miał warunek „pliki starsze niż 36 godzin” i działał o 7:30, po oknie backupu. Chronił przed backupem zawieszonym, ale nie przed takim, który zapycha dysk w godzinę. Są to dwa różne tryby awarii i trzeba zabezpieczyć oba.

Dlatego ustawiamy strażnika uruchamianego co 15 minut z progiem wolnego miejsca, u nas 20 GB. Po przekroczeniu progu:

  1. zatrzymuje procesy wp-cron sklepu, które niosą zadanie backupu,
  2. usuwa zdarzenie updraft_backup_resume i dane zadania updraft_jobdata_*, bo bez tego UpdraftPlus wraca przy następnym wywołaniu crona i dokańcza zapychanie,
  3. przenosi paczki na osobny wolumen poleceniem mv, nie rm, bo to może być jedyna kopia.

Przy testach wyszły dwie pułapki. Pierwsza wersja szukała procesów przez pgrep -f wp-cron.php, co łapało też powłokę SSH zawierającą ten ciąg w linii poleceń. Skrypt musi dopasować pełną ścieżkę i sprawdzić, że proces to php. kill -9 przerywa zadanie bez sprzątania, co przy zawieszonym backupie jest tu celowe:

P=/var/www/html/nazwa-sklepu   # ścieżka instalacji sklepu
for pid in $(pgrep -f "$P/wp-cron.php"); do
  cmd=$(tr '\0' ' ' < /proc/$pid/cmdline)
  case "$cmd" in *php*"$P/wp-cron.php"*) kill -9 "$pid";; esac
done

Druga: katalog /var/log ma grupę syslog, więc bez dyrektywy su root syslog logrotate po cichu pomija rotację, uznając uprawnienia za niebezpieczne. Reguła wygląda dobrze, ale nie robi nic.

Uwaga o drugim dysku. Wpis o zamontowaniu wolumenu w docker-compose.yml nie działa, dopóki kontener nie zostanie utworzony od nowa. Symlink na hoście też nie pomoże, bo wewnątrz kontenera katalog /mnt jest pusty. Sprawdź df z poziomu kontenera, nie hosta: ma pokazać drugi dysk.

Co ustawić w sklepie WooCommerce od razu?

  • alert przy wolnym miejscu poniżej 20% na każdym wolumenie,
  • rotację logów aplikacji i Dockera,
  • retencję kopii UpdraftPlus i zdalny magazyn, a staging na osobnym dysku,
  • wykluczenie z kopii katalogów, które same są kopiami (na przykład backupy wtyczki do obrazów),
  • kontrolę koszyka, nie tylko strony głównej, w monitoringu zewnętrznym,
  • wyłączanie debug logów po testach.

Szerzej o tym, co mierzyć poza dostępnością, piszemy w artykule o monitoringu sklepu WooCommerce i PrestaShop.

Kiedy zlecić to specjalistom?

Gdy sklep stoi, a nie wiadomo, co zjadło miejsce i w jakiej kolejności uruchamiać kontenery, żeby nie pogłębić awarii. W ASAPDevs przywracamy sklep, ustalamy przyczynę i ustawiamy zabezpieczenia w ramach opieki nad WordPressem. Gdy liczy się czas reakcji, zobacz Pogotowie IT.

Źródła: dokumentacja Redis, Persistence (zachowanie stop-writes-on-bgsave-error); Cloudflare, Error 521: Web server is down.

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

Sklep padł albo dysk jest prawie pełny?

Kamil Perzowski, ASAPDevs
Kamil Perzowski
CEO & Co-founder, ASAPDevs
Przywracamy sklep, ustalamy co zjadło miejsce i ustawiamy alerty oraz rotację logów. Pilne? Zadzwoń: +48 884 220 764.
★★★★★
Kapitalny kontakt, błyskawiczne wykonanie, super cena. Na pewno skorzystam ponownie. Polecam z czystym sumieniem!
Marcin P., opinia w Google
  1. Czytam zgłoszenie i odpisuję z pytaniami albo propozycją terminu rozmowy.
  2. Krótka rozmowa o zakresie, dostępach i terminie.
  3. Dostajesz plan i wycenę. Decydujesz, bez zobowiązań.

Wolisz od razu porozmawiać? +48 884 220 764 · [email protected]

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

FAQ

Pytania i odpowiedzi

Co znaczy błąd 521 w sklepie za Cloudflare?

+
Cloudflare działa, ale serwer origin nie odpowiada na jego połączenia. Przyczyną bywa wyłączony serwer WWW, padnięty kontener albo proxy, które nie wstało po awarii. Pełny dysk to jedna z częstszych przyczyn, bo zatrzymuje bazę, proxy i cache naraz.

Dlaczego strona główna działa, a koszyk i wp-admin zwracają 521?

+
Cloudflare potrafi podać stronę główną z pamięci podręcznej, także gdy origin nie żyje (dopóki wpis jest ważny). Koszyk, panel i REST API są dynamiczne, więc muszą dotrzeć do serwera. Dlatego sprawdzaj koszyk i adresy dynamiczne, a nagłówek CF-Cache-Status pokaże, czy odpowiedź przyszła z cache, zamiast patrzeć na samą stronę główną.

Co oznacza MISCONF Redis is configured to save RDB snapshots?

+
Redis nie może zapisać migawki na dysk, więc przy domyślnym stop-writes-on-bgsave-error odrzuca wszystkie zapisy. Object cache w WordPressie przestaje działać, a w logach pojawiają się błędy SET i ZADD. Najczęstsza przyczyna to brak miejsca na dysku.

Czy UpdraftPlus może zapełnić dysk serwera?

+
Tak. Wtyczka pakuje kopię najpierw lokalnie, w katalogu wp-content/updraft, a dopiero potem wysyła ją do zdalnego magazynu. Przy kilkudziesięciu gigabajtach uploadów i urwanym wysyłaniu paczki zostają na dysku produkcyjnym.

Czy docker ps -a wystarczy, żeby sprawdzić, czy kontenery żyją?

+
Nie. Po awarii dysku docker ps -a pokazywał „Up 33 hours” przy kontenerach, które dawno padły z kodem 128. Stan trzeba czytać z docker inspect, polami State.Status i State.ExitCode.

Przeczytaj też