Les caches de Drupal7 : base de données et Memcached

Décorticons un peu le système de cache de Drupal.

Cache des pages et cache Drupal (backend) :

Accéder à la page de configuration des caches via /admin/config/development/performance.

Cocher la case « Mettre en cache les pages pour les utilisateurs anonymes » dans Configuration>Performances

Régler les temps de caches à

  • 1 minute (60sec) pour la durée de vie minimale de la mémoire cache
  • 5 minutes pour l’expiration des pages en cache

(à vous de choisir les temps que vous souhaitez, évidemment…)

Explications

Le 1er temps agit sur le temps de vie du cache Drupal (celui stocké en base ou Memcached ou autre backend de votre choix, BDD par défaut).
Le second agit sur le header HTTP « Cache-Control », qui dira à votre navigateur (et à un éventuel reverse proxy tel Varnish) combien de temps cette page est valable, et dans ce cas, le navigateur n’ira pas chercher une autre version de cette page tant que ce temps n’est pas échu.

Cf bootstrap.php, lg 2278 (à l’h où j’écrit cet article)

$cache = drupal_page_get_cache();
if (is_object($cache)) {
  header('X-Drupal-Cache: HIT');
 // (...)
}
else {
  header('X-Drupal-Cache: MISS');
}

c’est donc là qu’est ajouté le header HTTP indiquant que la page provient du cache Drupal.
Exemple d’utilisation avec Firefox :

  • en faisant F5, on rafraichit la page, mais si le navigateur l’a en cache, il n’appelle pas le serveur
  • en faisant CTRL+F5, le navigateur va chercher la page sur le serveur :
    • Si Drupal l’a en cache, il y aura l’en-tete HTTP X-Drupal-Cache: HIT,
    • Si le TTL est dépassé, Drupal recalcule la page, on aura X-Drupal-Cache: MISS

Bon à savoir : lorsqu’un noeud est enregistré, le cache de page et de block sont vidés, via la fonction cache_clear_all(), appelée au niveau du module « node », dans node.pages.inc, en bas de la fonction « node_form_submit ».
Drupal ne vide pas le cache lorsque les contenus/menus sont enregistrés, il note l’heure d’enregistrement du contenu dans la variable cache_flush_<bin>. Ainsi, à chaque fois que le cache sera intérrogé, le garbage collector regardera le (cache_lifetime + cache_flush_<bin>). S’il est inférieur à REQUEST_TIME, il invalide le cache.

Ensuite, il repasse cache_flush_<bin> à 0. Du coup, tant qu’il n’y a pas de changement de contenu, le cache ne sera pas invalidé. Meme si cache_lifetime est révolu.

 

Pour info, la mise en cache d’une page est faite dans common.inc, lg 5038, fonction drupal_page_set_cache().

Pour la mise en cache d’un block, le cid est déterminé par _block_get_cache_id() dans modules/block.module

 

Ca se corse avec le module « memcache »

Dans ce module, la méthode « clear » ne fonctionne pas comme le backend « base de données » :
alors que le module BDD vidange bien le cache page et cache block quand la méthode « cache_clear_all » est appelée, avec le backend memcache, il n’en est rien !!!

Autrement dit, si un noeud est mis à jour, pas de clear_cache_all fonctionnel…

if (!isset($cid)) {
return;
}

A priori, après cette découverte, je conseille d’utiliser la base (ou autre backend) pour le cache de page et de block, surtout si vous avez un Varnish devant, qui évitera de toutes façons que la BDD ne travaille. Dans le cas contraire, il faudra s’orienter vers d’autres backend tel MongoDB ?