Bonjour toutes et tous,
je viens de passer un peu de temps d’analyse sur la manière dont fonctionne le cache et j’avoue que la documentation me laisse perplexe. Aussi, j’aimerais votre avis pour corriger mes éventuelles erreurs de compréhension, et trancher une bonne fois pour toutes entre utiliser <INCLURE>
ou #INCLURE
.
La documentation
Essentiellement je me suis basé sur <INCLURE> d'autres squelettes - SPIP mais aussi Du php dans le squelette à la place de #SESSION ou #CACHE 0 - SPIP-Contrib
Qui dit essentiellement:
<INCLURE{fond=…}> et [(#INCLURE{fond=…})] ont donc des fonctionnements différents :
- avec <INCLURE{fond=…}> chaque squelette inclus a un cache indépendant. Autrement dit, cette syntaxe provoque l’inclusion des pages à chaque visite d’un internaute, que celle-ci concerne une page déjà en cache ou non.
- avec [(#INCLURE{fond=…})], la page principale appelante contient, en cache, l’intégralité du code généré, et les fichiers inclus n’ont pas de cache séparé.
et contrib spip:
Pour le choix entre
<INCLURE>
(inclusion avec cache indépendant) et #INCLURE (inclusion dans le cache du contexte d’appel) et pour l’usage de #SESSION voici une régle de base :
- règle N°1 : utiliser
<INCLURE>
partout
- règle N°2 : ne jamais utiliser #INCLURE ni #MODELE, surtout lorsque le squelette de l’inclusion est un peu complexe.
- règle N°3 : utiliser #INCLURE ou #MODELE uniquement si on a besoin de conditionner l’affichage au moment de l’inclusion et utiliser les parties conditionnelles avant/après de la balise #INCLURE, ou besoin d’appliquer un filtre au résultat.
Mes tests
Je m’excuse d’avance pour ceux qui connaissant tout cela, mais ça pourra peut être servir à d’autres donc je vais quand même détailler un peu le truc.
Le code
J’utilise un squelette simplissime que j’appelle test12.html
hello squelette
<INCLURE{fond=inc_test}>
qui inclut une noisette inc_test.html
:
<br>
coucou noisette !!!!!!!!!!!!!!!!!!
<br>
Nombre =
<?php echo random_int(1,42); ?>
<br>
Nous sommes le <time datetime='#DATE'>[(#DATE|date_iso)]</time>
#INCLURE statique
Pour ce test j’utilise donc [(#INCLURE{fond=inc_test})]
dans mon squelette.
Je vide le cache et j’obtiens:
- un squelette PHP
skel/html_27fe7002f3ad6db46f7f78e9b6748c5d.php
:
<?php
/*
* Squelette : squelettes/test12.html
* Date : Thu, 25 Jan 2024 13:32:42 GMT
* Compile : Thu, 25 Jan 2024 13:34:52 GMT
* Boucles :
*/
//
// Fonction principale du squelette squelettes/test12.html
// Temps de compilation total: 0.197 ms
//
function html_27fe7002f3ad6db46f7f78e9b6748c5d($Cache, $Pile, $doublons = array(), $Numrows = array(), $SP = 0) {
if (isset($Pile[0]["doublons"]) AND is_array($Pile[0]["doublons"]))
$doublons = nettoyer_env_doublons($Pile[0]["doublons"]);
$connect = '';
$page = (
'hello squelette
' .
recuperer_fond( 'inc_test' , array(), array('compil'=>array('squelettes/test12.html','html_27fe7002f3ad6db46f7f78e9b6748c5d','',3,$GLOBALS['spip_lang'])), _request('connect') ?? ''));
return analyse_resultat_skel('html_27fe7002f3ad6db46f7f78e9b6748c5d', $Cache, $page, 'squelettes/test12.html');
}
?>
- ce code php permet de créer un fichier de cache
cache/calcul/ba81/e6d5.cache
qui contient le code SPIP transpilé (calculé dans le langage SPIP si j’ai bien suivi) et du code PHP:
<br>
coucou noisette !!!!!!!!!!!!!!!!!!
<br>
Nombre =
<?php echo random_int(1,42); ?>
<br>
Nous sommes le <time datetime='2024-01-25 14:34:52'>2024-01-25T13:34:52Z</time>
- et j’obtiens également le code pour toute ma page dans
cache/calcul/93fe/3a17.cache
qui inclut le cache précédent (au détail prêt que le PHP a été interprété!!!):
hello squelette
<br>
coucou noisette !!!!!!!!!!!!!!!!!!
<br>
Nombre =
21<br>
Nous sommes le <time datetime='2024-01-25 14:34:52'>2024-01-25T13:34:52Z</time>
Si je rappelle plusieurs fois la page mon nombre aléatoire et ma date ne change plus à moins de « calculer » la page à nouveau ce qui redéclenche une exécution dans mon squelette PHP. Spip regénère alors à nouveau les caches. Il y a une petite différence avec ce qui est écrit dans la doc
et les fichiers inclus n’ont pas de cache séparé
mais bref, c’est fonctionnellement identique et à part un peu plus de place prise dans le cache, la doc est conforme au résultat.
<INCLURE> dynamique
Pour ce test j’utilise donc <INCLURE{fond=inc_test}>
dans mon squelette.
Je vide le cache et j’obtiens:
- un squelette PHP légèrement différent
skel/html_27fe7002f3ad6db46f7f78e9b6748c5d.php
: (j’ai stippé les parties identiques, notez seulement l’apparition duecho
avantrecuperer_fond
)
$page = (
'hello squelette
' .
'<'.'?php echo recuperer_fond( ' . argumenter_squelette('inc_test') . ', array(\'lang\' => ' . argumenter_squelette($GLOBALS["spip_lang"]) . '), array("compil"=>array(\'squelettes/test12.html\',\'html_27fe7002f3ad6db46f7f78e9b6748c5d\',\'\',3,$GLOBALS[\'spip_lang\'])), _request(\'connect\') ?? \'\');
?'.'>');
- j’ai toujours le même cache pour ma noisette
cache/calcul/ba81/e6d5.cache
qui contient le code SPIP transpilé - en revanche le cache de la page a radicalement changé:
hello squelette
<?php echo recuperer_fond( 'inc_test', array('lang' => 'fr'), array("compil"=>array('squelettes/test12.html','html_27fe7002f3ad6db46f7f78e9b6748c5d','',3,$GLOBALS['spip_lang'])), _request('connect') ?? '');
?>
On n’a plus de texte brut, mais un echo
qui va aller rééxécuter le code contenu dans le cache de la première noisette. Avec ce sytème, mon nombre aléatoire fonctionne bien (à chaque appel PHP va réinterprêter random
) mais ma date ne change touours pas à moins d’un nouveau calcul qui peut intervenir si:
- on calcul la page à nouveau
- le cache arrive en fin de vie
- un évènement invalide le cache de spip (publication d’article, commentaire, modification, etc…)
Mesures
J’ai pris 250 vraies urls de mon site (avec des images et une vraie mise en page), et j’ai fait un curl multi threadé pour simuler 5 « hits » en simultané sur chaque article. Je prend le temps cumulé de ces 5 « internautes » pour chaque URL, et je moyenne le tout.
Dans le squelette de la page, j’ai soit mis uniquement des <INCLURE>
soit des #INCLURE
en fonction du test.
edit: j’ai réalisé ces mesures avec la compression des caches désactivée (je l’avais enlevé pour mes analyses, et oublié de la remettre pour les tests). Les tailles réelles de caches sont donc en vrai plus petites, mais ça ne change pas l’ordre des choses.
<INCLURE>
:- Je commence avec un cache vide: 965ms en moyenne
- Puis au 2ème passage: 184ms
- le cache pèse 30Mo
#INCLURE
:- Je commence avec un cache vide:: 600ms en moyenne
- Puis au 2ème passage : 90ms
- le cache pèse 48Mo
Je suis très surpris des différences très significatives de timings. C’est énorme je trouve. Bon je ne comprends pas vraiment pourquoi au 1er passage le #INCLURE
est 300ms plus rapide alors que c’est plus de travail pour lui. Sur d’autres mesures avec moins d’urls je trouve un timing similaire à <inclure>
. Passons.
En terme de service par contre, on va 2X plus vite avec un cache statique qu’en dynamique. Au prix de 50% de taille de cache en plus. L’explosion de la taille du cache s’explique facilement, par contre les multipes echo recuperer_fond()
(qui font des accès disques si le cache est dans le filesystem) des caches noisettes en dynamique semblent assez pénalisants…
Mes questions
Merci d’avoir lu jusque là!
Déjà, est ce que c’est quelque chose que vous constatez vous aussi? Est ce que mon test est biaisé quelque part?
Parce que du coup, quand je regarde la doc et spip contrib et que je vois:
règle N°1 : utiliser
<INCLURE>
partout
règle N°2 : ne jamais utiliser #INCLURE ni #MODELE, surtout lorsque le squelette de l’inclusion est un peu complexe.
Un abus de l’emploi des #INCLURE (statiques) risque donc d’augmenter le volume de cache et il faut éviter d’y avoir recours et ne les employer que quand on a pas le choix, c’est à dire
- en cas d’affichage conditionnel [ avant(#INCLURE)apres]
- ou en cas d’appel d’un filtre [(#INCLURE|filtrer)] .
et bien je suis assez surpris. Certes, le volume de cache est significativement plus important mais… à l’heure des disques SSD en To et des serveurs blindés de RAM, est il pertinent de continuer à recommander du cache dynamique? En statique, le gain pour le visiteur (et le référencement) est énorme!
Évidemment, si du code PHP traine dans les noisettes un cache statique peut être dangereux (ça dépend de ce qui est fait), mais du coup j’aurais plutôt tendance à inverser la logique non? Utilisez du cache statique partout SAUF si vous êtes coincés avec un besoin données dynamiques et dans ce cas là utilisez le cache dynamique.
Le seul bémol que je peux mettre à mon analyse car je n’ai pas testé ce sont les grosses tailles de cache si on utilise REDIS ou un cache en RAM. Le fait de ne pas partager les caches de noisettes entre 2 pages pourrait peut être être pesant sur un site à gros volume…
Bref, j’aimerais vraiment avoir vos retours, peut être que j’ai loupé un truc? Merci à vous!
cpol0