Dois-je utiliser l'API transitoire pour stocker une chaîne HTML ou un objet?

18

Supposons qu'il existe un plugin qui affiche 20 articles associés (pour chaque article) avec une requête très complexe. Et puis en utilisant les données de cette requête, il crée une mise en page HTML complexe. Il convient également de noter que le plugin est public et peut être installé sur n'importe quel serveur avec n'importe quelle configuration.

Quelque chose comme:

/* 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 .= ...;
}

Mes questions sont donc:

  • Quelle est la manière la plus sûre et la plus correcte de mettre en cache ces données?
  • Dois-je utiliser l'API transitoire pour mettre en cache le $related_poststableau ou la $html_outputchaîne? Si je cache la $html_ouputchaîne, atteindra-t-il une limite de taille maximale? Dois-je peut-être le gzip, avant d'enregistrer?
  • Dois-je utiliser l'API transitoire ici?
Marvin3
la source

Réponses:

18

Dois-je utiliser l'API transitoire ici?

Non.

Dans un stock, les transitoires d'installation de WordPress sont stockés dans la table wp_options et nettoyés uniquement lors des mises à niveau principales. Supposons que vous ayez 50 000 publications, soit 50 000 lignes supplémentaires dans le tableau des options. De toute évidence, ils sont définis sur autoload = no, donc cela ne va pas consommer toute votre mémoire, mais il y a une autre mise en garde.

Le champ de chargement automatique dans la table d'options n'a pas d'index, ce qui signifie que l'appel à wp_load_alloptions()va effectuer une analyse complète de la table. Plus vous avez de lignes, plus cela prendra de temps. Plus vous écrivez dans la table des options, moins les caches internes de MySQL sont efficaces.

Si les données mises en cache sont directement liées à une publication, il vaut mieux les stocker dans la méta-publication. Cela vous permettra également d'économiser une requête chaque fois que vous devrez afficher le contenu mis en cache, car les méta-caches de post sont (généralement) amorcées lors de la récupération de post dans WP_Query.

Votre structure de données pour la méta-valeur peut varier, vous pouvez avoir un horodatage et effectuer votre requête coûteuse si la valeur en cache est obsolète, un peu comme un transitoire se comporterait.

Une autre chose importante à garder à l'esprit est que les transitoires WordPress peuvent être volatils dans des environnements avec une mise en cache d'objets persistante. Cela signifie que si vous stockez vos données en cache pendant 24 heures dans un transitoire, il n'y a absolument aucune garantie qu'elles seront disponibles dans 23 heures, ou 12, ou même 5 minutes. Le backend du cache d'objets pour de nombreuses installations est un magasin de valeurs-clés en mémoire tel que Redis ou Memcached, et s'il n'y a pas assez de mémoire allouée pour contenir des objets plus récents, les éléments plus anciens seront supprimés. C'est une énorme victoire pour l'approche du méta-stockage.

L'invalidation peut également être plus intelligente, c'est-à-dire pourquoi invalidez-vous les caches de messages associés dans X heures? Est-ce parce que certains contenus ont changé? Un nouveau message a été ajouté? Un nouveau tag a été attribué? En fonction de votre "requête complexe et volumineuse", vous pouvez choisir d'invalider UNIQUEMENT si quelque chose s'est produit qui va modifier les résultats de votre requête.

Dois-je utiliser l'API transitoire pour mettre en cache le tableau $ related_posts ou la chaîne $ html_output? Si je mets en cache la chaîne $ html_ouput, atteindra-t-il une limite de taille maximale? Dois-je peut-être le gzip, avant d'enregistrer?

Cela dépend beaucoup de la taille de votre chaîne, car ce sont les données qui vont circuler entre PHP, MySQL, etc. seulement 1 mb.

Combien de temps prend réellement votre "logique de rendu de mise en page complexe"? Exécutez-le via un profileur pour le savoir. Les chances sont que ce soit très rapide ne deviendra jamais un goulot d'étranglement.

Si tel est le cas, je suggérerais de mettre en cache les identifiants de publication. Pas les objets WP_Post, car ceux-ci contiendront le contenu complet de la publication, mais juste un tableau d'ID de publication. Ensuite, utilisez simplement un WP_Queryavec un post__inqui se traduira par une requête MySQL très rapide par clé primaire.

Cela dit, si les données nécessaires par élément sont assez simples, peut-être le titre, l'URL de la vignette et le permalien, vous pouvez stocker uniquement ces trois, sans les frais d'un aller-retour supplémentaire vers MySQL, et sans les frais de mise en cache du très long HTML cordes.

Wow, c'est beaucoup de mots, j'espère que ça aide.

kovshenin
la source
12

Tout le code WP n'est pas un code public

Si vous allez publier quelque chose de public, alors tout ce que kovshenin a dit est parfaitement valable.

Les choses sont différentes si vous allez écrire du code privé pour vous ou votre entreprise.

Le cache d'objets externes est un gros avantage, dans tous les cas

Pour définir un cache d'objets persistants externe est très recommandé , lorsque vous le pouvez.

Toutes les choses dites dans la réponse du kovshenin sur les transitoires et MySQL sont très vraies, et étant donné que WP lui-même et un tas de plugins utilisent le cache d'objets ... alors l'amélioration des performances que vous avez obtenue, vaut vraiment le (petit) effort de configuration un système de cache moderne comme Redis ou Memcached.

Les valeurs mises en cache peuvent ne pas être là: c'est bien

De plus, oui, un cache d'objets externe n'est pas fiable. Vous ne devriez jamais vous fier au fait qu'un transitoire est là. Vous devez vous assurer que cela fonctionne si la mise en cache n'est pas là où elle devrait être.

Le cache n'est pas un stockage, le cache est un cache.

Utiliser le cache de manière sélective

Voir cet exemple:

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;
}

En utilisant un code comme celui-ci, dans votre site privé, les performances du site peuvent s'améliorer considérablement , surtout si vous avez beaucoup d'utilisateurs.

Notez que:

  • Par défaut, le cache n'est pas utilisé lorsque le débogage est activé, donc, espérons-le, sur votre environnement de développement. Croyez-moi, le cache peut faire du débogage un enfer
  • Par défaut, le cache n'est également pas utilisé lorsque WP n'est pas configuré pour utiliser un cache d'objets externe. Cela signifie que tout le problème lié à MySQL n'existe pas, car vous n'utilisez aucun transitoire lorsqu'ils utilisent MySQL. Une alternative probablement plus simple serait d'utiliser des wp_cache_*fonctions , donc si aucun cache externe n'est configuré, le cache se produit en mémoire et la base de données n'est jamais impliquée.
  • L'utilisation du cache est filtrable, pour gérer certains cas marginaux que vous pouvez rencontrer

Pas d'échelle Web si pas de cache

Vous ne devriez pas essayer de résoudre les problèmes de vitesse avec le cache. Si vous avez des problèmes de vitesse, vous devez repenser votre code.

Mais pour faire évoluer un site Web à l'échelle du Web, le cache est assez nécessaire .

Et souvent (mais pas toujours) fragmenté, le cache contextuel est beaucoup plus flexible et adapté que la mise en cache agressive pleine page.

Vos questions:

Dois-je utiliser l'API transitoire ici?

Ça dépend .

Votre code consomme-t-il beaucoup de ressources? Sinon, il n'y a peut-être pas besoin de cache. Comme je l'ai dit, ce n'est pas qu'une question de vitesse. Si votre code s'exécute rapidement mais qu'il nécessite un tas de CPU et de mémoire pour quelques utilisateurs ... que se passe-t-il lorsque vous avez 100 ou 1000 utilisateurs simultanés?

Si vous réalisez que le cache serait une bonne idée ..

... et est un code public: probablement non . Vous pouvez envisager de mettre en cache de manière sélective, comme dans mon exemple ci-dessus dans le code public, mais c'est généralement mieux si vous laissez ces décisions aux implémenteurs.

... et est un code privé: très probablement oui . Mais même pour le code privé, la mise en cache sélective est toujours une bonne chose, par exemple pour le débogage.

N'oubliez pas, de toute façon, que les wp_cache_*fonctions peuvent vous donner accès au cache sans risque de polluer la base de données.

Dois-je utiliser l'API transitoire pour mettre en cache le tableau $ related_posts ou la chaîne $ html_output?

Cela dépend de beaucoup de choses. Quelle est la taille de la chaîne? Quel cache externe utilisez-vous? Si vous allez mettre en cache des publications, le stockage de l'ID sous forme de tableau peut être une bonne idée, interroger un nombre décent de publications par leur ID est assez rapide.

Notes finales

L'API transitoire est probablement l'une des meilleures choses de WordPress. Grâce aux plugins que vous pouvez trouver pour tout type de systèmes de cache, cela devient une stupide API simple pour un grand nombre de logiciels qui peuvent fonctionner sous le capot.

En dehors de WordPress, une telle abstraction qui fonctionne tout de suite avec un tas de systèmes de mise en cache différents et vous permet de passer d'un système à un autre sans effort est très difficile à trouver.

Vous pouvez rarement m'entendre dire que WordPress est meilleur que d'autres choses modernes, mais l'API transitoire est l'une des rares choses qui me manquent lorsque je ne travaille pas avec WordPress.

Le cache est sûrement difficile, ne résout pas les problèmes de code et n'est pas une solution miracle, mais c'est quelque chose dont vous avez besoin pour créer un site à fort trafic qui fonctionne.

L'idée WordPress d'utiliser une table MySQL sous-optimisée pour faire du cache est assez folle, mais il n'est pas préférable de vous tenir à l'écart du cache simplement parce que WordPress, par défaut, le fait.

Il vous suffit de comprendre comment les choses fonctionnent, puis de faire votre choix.

gmazzap
la source
2

Les réponses précédentes ont déjà mis en évidence le caractère obligatoire " Cela dépend ", auquel je souscris pleinement.

Je voudrais cependant ajouter une recommandation, basée sur la façon dont je " suppose " que cela serait mieux fait dans le scénario que vous décrivez ci-dessus.

Je n'utiliserais pas les transitoires dans ce cas, mais plutôt le Post Meta , à cause d'un avantage que ce dernier a: le contrôle .

Comme vous devez mettre en cache les données par publication, la quantité de données que vous allez mettre en cache dépend du nombre de publications et augmentera avec le temps. Une fois que vous avez dépassé un certain nombre de publications, vous pouvez atteindre les limites de la mémoire que votre cache d'objets est autorisé à utiliser, et il commencera à effacer les données précédemment mises en cache de la mémoire avant son expiration. Cela pourrait conduire à une situation, où vous avez un afflux important de visiteurs, où chaque visiteur déclenchera le "SQL trop complexe" à chaque demande de page, et votre site sera complètement enlisé.

Si vous mettez en cache les données dans votre Post Meta, vous pouvez non seulement contrôler la façon dont elles sont stockées et récupérées, mais vous pouvez également contrôler exactement comment elles sont mises à jour. Vous ajouteriez un travail cron pour cela qui ne s'exécute qu'à des périodes où il y a moins ou pas de trafic vers le site. Ainsi, la «requête lente» n'est jamais rencontrée par les vrais utilisateurs du site, et vous pouvez même la précharger, de sorte que le travail est déjà fait lorsque le premier visiteur frappe.

Gardez à l'esprit que toute mise en cache est un compromis! C'est pourquoi la réponse habituelle est "Cela dépend". et pourquoi il n'y a pas de "Saint Graal de mise en cache".

Alain Schlesser
la source