Czy powinienem używać Transient API do przechowywania ciągu HTML lub obiektu?

18

Załóżmy, że istnieje wtyczka, która wyświetla 20 powiązanych postów (dla każdego postu) z bardzo złożonym zapytaniem. A następnie przy użyciu danych z tego zapytania buduje złożony układ HTML. Należy również zauważyć, że wtyczka jest publiczna i można ją zainstalować na dowolnym serwerze z dowolną konfiguracją.

Coś jak:

/* complex and large query */
$related_posts = get_posts( ... );

$html_output = '';
foreach($related_posts as $key => $item) {
     /* complex layout rendering logic (but not as slow as the previous query) */   
     $html_output .= ...;
}

Więc moje pytania to:

  • Jaki jest najbezpieczniejszy i najbardziej poprawny sposób buforowania takich danych?
  • Czy powinienem używać Transient API do buforowania $related_poststablicy lub $html_outputłańcucha? Jeśli buforuję $html_ouputciąg, czy osiągnie on limit maksymalnego rozmiaru? Czy powinienem go zgzipować przed zapisaniem?
  • Czy powinienem w ogóle korzystać z Transient API?
Marvin3
źródło

Odpowiedzi:

18

Czy powinienem w ogóle korzystać z Transient API?

Nie.

Na stanie WordPress instaluje transjenty w tabeli wp_options i są czyszczone tylko podczas aktualizacji podstawowych. Załóżmy, że masz 50 000 postów, czyli 50 000 dodatkowych wierszy w tabeli opcji. Oczywiście są ustawione na autoload = nie, więc nie zajmie to całej twojej pamięci, ale jest jeszcze jedno zastrzeżenie.

Pole automatycznego ładowania w tabeli opcji nie ma indeksu, co oznacza, że ​​wywołanie wp_load_alloptions()do wykona pełne skanowanie tabeli. Im więcej masz rzędów, tym dłużej to zajmie. Im częściej piszesz do tabeli opcji, tym mniej wydajne są wewnętrzne pamięci podręczne MySQL.

Jeśli buforowane dane są bezpośrednio związane z postem, lepiej przechowywać je w meta postu. Pozwoli to również zapisać zapytanie za każdym razem, gdy trzeba wyświetlić zawartość pamięci podręcznej, ponieważ meta-pamięci podręczne są (zwykle) przygotowywane podczas pobierania wiadomości w WP_Query.

Struktura danych dla meta wartości może się różnić, możesz mieć znacznik czasu i wykonać kosztowne zapytanie, jeśli buforowana wartość jest nieaktualna, podobnie jak zachowałby się stan przejściowy.

Inną ważną rzeczą, o której należy pamiętać, jest to, że transjenty WordPress mogą być niestabilne w środowiskach z trwałym buforowaniem obiektów. Oznacza to, że jeśli przechowujesz dane buforowane przez 24 godziny w stanie przejściowym, nie ma absolutnie żadnej gwarancji, że będą one dostępne za 23 godziny lub 12, a nawet 5 minut. Backend pamięci podręcznej obiektów dla wielu instalacji to magazyn kluczy i wartości w pamięci, taki jak Redis lub Memcached, a jeśli nie będzie wystarczającej ilości przydzielonej pamięci, aby zmieścić nowsze obiekty, starsze elementy zostaną eksmitowane. To ogromna wygrana dla metody meta storage.

Unieważnienie może być również mądrzejsze, tzn. Dlaczego unieważniasz powiązane pamięci podręczne wpisów w ciągu X godzin? Czy to dlatego, że niektóre treści się zmieniły? Dodano nowy post? Nowy tag został przypisany? W zależności od „złożonego i dużego zapytania” możesz anulować TYLKO, jeśli wydarzy się coś, co zmieni wyniki Twojego zapytania.

Czy powinienem używać Transient API do buforowania tablicy $ related_posts array, czy $ html_output string? Jeśli buforuję łańcuch $ html_ouput, czy osiągnie on limit maksymalnego rozmiaru? Czy powinienem go zgzipować przed zapisaniem?

Zależy to w dużej mierze od rozmiaru łańcucha, ponieważ są to dane, które będą przepływać między PHP, MySQL itp. Musisz bardzo mocno spróbować osiągnąć limity MySQL, ale na przykład domyślny limit dla obiektu Memcached to tylko 1 mb.

Ile faktycznie zajmuje „logika renderowania złożonego układu”? Przeprowadź go przez profiler, aby się dowiedzieć. Są szanse, że jest bardzo szybki, nigdy nie stanie się wąskim gardłem.

W takim przypadku sugeruję buforowanie identyfikatorów postów. Nie obiekty WP_Post, ponieważ będą one zawierać pełną treść postów, ale tylko tablicę identyfikatorów postów. Następnie po prostu użyj WP_Queryz, post__inktóra spowoduje bardzo szybkie zapytanie MySQL według klucza podstawowego.

To powiedziawszy, jeśli dane potrzebne na element są dość proste, na przykład tytuł, adres URL miniatury i bezpośredni link, możesz przechowywać tylko te trzy, bez dodatkowych kosztów podróży w obie strony do MySQL i bez nadmiernego buforowania bardzo długiego HTML smyczki.

Wow, to dużo słów, nadzieja, która pomaga.

koshenin
źródło
12

Nie wszystkie kody WP są kodami publicznymi

Jeśli zamierzasz wydać coś publicznego, wszystkie rzeczy, które powiedział kovshenin , są całkowicie poprawne.

Sytuacja wygląda inaczej, jeśli zamierzasz napisać prywatny kod dla siebie lub swojej firmy.

Zewnętrzna pamięć podręczna obiektów to w każdym razie duża zaleta

W miarę możliwości bardzo zalecane jest ustawienie zewnętrznej pamięci podręcznej obiektów trwałych .

Wszystkie rzeczy powiedziane w odpowiedzi kovshenina na temat stanów nieustalonych i MySQL są bardzo prawdziwe, a biorąc pod uwagę, że sama WP i kilka wtyczek korzysta z pamięci podręcznej obiektów ... to poprawa wydajności, którą otrzymałeś, absolutnie warta (małego) wysiłku w konfiguracji nowoczesny system pamięci podręcznej, taki jak Redis lub Memcached.

Wartości w pamięci podręcznej mogą nie być dostępne: w porządku

Ponadto tak, pamięć podręczna obiektów zewnętrznych nie jest niezawodna. Nigdy nie powinieneś polegać na fakcie, że istnieje stan przejściowy. Musisz upewnić się, że działa, jeśli buforowane nie są tam, gdzie powinny być.

Pamięć podręczna nie jest przechowywana, pamięć podręczna to pamięć podręczna.

Używaj pamięci podręcznej wybiórczo

Zobacz ten przykład:

function my_get_some_value($key) {
   // by default no cache when debug and if no external object_cache
   $defUse = ! (defined('WP_DEBUG') && WP_DEBUG) && wp_using_ext_object_cache();
   // make the usage of cache filterable
   $useCache = apply_filters('my_use_cache', $defUse);
   // return cached value if any
   if ($useCache && ($cached = get_transient($key))) {
     return $cached;
   }
   // no cached value, make sure your code works with no cache
   $value = my_get_some_value_in_some_expensive_way();
   // set cache, if allowed
   $useCache and set_transient($key, $value, HOUR_IN_SECONDS);

   return $value;
}

Używając takiego kodu w swojej prywatnej witrynie, wydajność witryny może się znacznie poprawić , szczególnie jeśli masz wielu użytkowników.

Uwaga:

  • Domyślnie pamięć podręczna nie jest używana, gdy debugowanie jest włączone, więc mam nadzieję, że w środowisku programistycznym. Uwierz mi, pamięć podręczna może sprawić, że debugowanie stanie się piekłem
  • Domyślnie pamięć podręczna nie jest również używana, gdy WP nie jest ustawione na używanie pamięci podręcznej obiektów zewnętrznych. Oznacza to, że cały problem związany z MySQL nie istnieje, ponieważ nie używasz przejściowych, gdy używają MySQL. Prawdopodobnie łatwiejszą alternatywą byłoby użycie wp_cache_*funkcji , więc jeśli nie zostanie skonfigurowana zewnętrzna pamięć podręczna, pamięć podręczna dzieje się w pamięci i baza danych nigdy nie jest zaangażowana.
  • Użycie pamięci podręcznej można filtrować, aby obsłużyć niektóre przypadki brzegowe, które możesz napotkać

No Webscale If No Cache

Nie powinieneś próbować rozwiązywać problemów z prędkością pamięci podręcznej. Jeśli masz problemy z prędkością, powinieneś przemyśleć kod.

Ale aby skalować stronę internetową w skali internetowej, pamięć podręczna jest dość wymagana .

Wiele razy (ale nie zawsze) fragmentaryczna, kontekstowa pamięć podręczna jest znacznie bardziej elastyczna i odpowiednia niż agresywne buforowanie na całej stronie.

Twoje pytania:

Czy powinienem w ogóle korzystać z Transient API?

To zależy .

Czy Twój kod zużywa dużo zasobów? Jeśli nie, być może nie ma potrzeby buforowania. Jak już powiedziano, nie jest to tylko kwestia prędkości. Jeśli twój kod działa szybko, ale wymaga kilku procesorów i pamięci dla kilku użytkowników ... co się stanie, gdy masz 100 lub 1000 równoczesnych użytkowników?

Jeśli zdasz sobie sprawę, że pamięć podręczna byłaby dobrym pomysłem ..

... i jest kodem publicznym: prawdopodobnie nie . Możesz rozważyć buforowanie wybiórcze, jak w moim przykładzie powyżej w kodzie publicznym, ale zwykle lepiej jest, jeśli pozostawisz takie decyzje implementatorom.

... i jest prywatnym kodem: prawdopodobnie tak . Ale nawet w przypadku prywatnego kodu selektywne buforowanie jest nadal dobrą rzeczą, na przykład do debugowania.

Pamiętaj jednak, że wp_cache_*funkcje te zapewniają dostęp do pamięci podręcznej bez ryzyka zanieczyszczenia bazy danych.

Czy powinienem używać Transient API do buforowania tablicy $ related_posts array, czy $ html_output string?

To zależy od wielu rzeczy. Jak duży jest sznurek? Której zewnętrznej pamięci podręcznej używasz? Jeśli masz zamiar buforować posty, dobrym pomysłem może być przechowywanie identyfikatora jako tablicy, zapytanie odpowiedniej liczby postów według ich identyfikatora jest dość szybkie.

Uwagi końcowe

Transient API jest prawdopodobnie jedną z najlepszych rzeczy w WordPress. Dzięki wtyczkom, które można znaleźć dla dowolnego rodzaju systemów pamięci podręcznej, staje się głupim, prostym interfejsem API dla dużej liczby programów, które mogą działać pod maską.

Poza WordPress bardzo trudno jest znaleźć taką abstrakcję, która działa od razu z zestawem różnych systemów buforowania i umożliwia przełączanie się z jednego systemu do drugiego bez żadnego wysiłku.

Rzadko słyszysz, jak mówię, że WordPress jest lepszy niż inne nowoczesne rzeczy, ale przejściowy interfejs API jest jedną z niewielu rzeczy, za którymi tęsknię, gdy nie pracuję z WordPress.

Z pewnością pamięć podręczna jest trudna, nie rozwiązuje problemów z kodem i nie jest srebrną kulą, ale jest czymś, czego potrzebujesz, aby zbudować działającą witrynę o dużym ruchu.

Pomysł WordPressa na użycie niedostatecznie zoptymalizowanej tabeli MySQL do buforowania jest dość szalony, ale nie lepiej trzymać się z dala od bufora tylko dlatego, że WordPress domyślnie to robi.

Musisz tylko zrozumieć, jak to działa, a następnie dokonać wyboru.

gmazzap
źródło
2

Poprzednie odpowiedzi podkreślały już obowiązkowe „ To zależy ”, na co w pełni się zgadzam.

Chciałbym jednak dodać zalecenie oparte na tym, jak „ przypuszczam ”, że najlepiej to zrobić w opisanym powyżej scenariuszu.

W tym przypadku nie użyłbym Transjentów , ale raczej Post Meta , z powodu jednej korzyści, jaką ma ta ostatnia: Kontrola .

Ponieważ musisz buforować dane na zasadzie post-post, ilość danych, które będziesz buforować, zależy od liczby postów i z czasem będzie rosła. Gdy przekroczysz pewną liczbę postów, możesz przekroczyć limit pamięci, z którego może korzystać pamięć podręczna obiektu, i zacznie ona kasować wcześniej buforowane dane z pamięci, zanim upłynie termin ważności. Może to prowadzić do sytuacji, w której masz duży napływ odwiedzających, gdzie każdy odwiedzający wywoła „zbyt skomplikowany kod SQL” przy każdym żądaniu strony, a Twoja witryna całkowicie się ugrzęźnie.

Jeśli buforujesz dane w meta Post, możesz nie tylko kontrolować sposób ich przechowywania i pobierania, ale także dokładnie kontrolować sposób ich aktualizacji. Dodałbyś do tego zadanie CRON, które działa tylko w okresach, w których ruch w witrynie jest mniejszy lub nie ma go wcale. Tak więc „powolne zapytanie” nigdy nie jest spotykane przez prawdziwych użytkowników witryny, a nawet można je wstępnie załadować, aby praca była wykonywana, gdy trafi pierwszy użytkownik.

Pamiętaj, że całe buforowanie jest kompromisem! Dlatego zwykle odpowiedź brzmi „to zależy”. i dlaczego nie ma „świętego graala z pamięci podręcznej”.

Alain Schlesser
źródło