Dans un environnement mutualisé, il est quasiment impossible d’avoir à disposition un système de cache de type mémoire comme «memcache» ou un gestionnaire de cache d’opcode comme « APC ».
Pour améliorer les performances de votre application, il vous reste deux possibilités :

  • améliorer le code PHP,
  • mettre en place un système de cache fichier.

Nous ne traiterons pas du premier point et allons voir comment améliorer une application PHP en utilisant un système de cache fichier en PHP.

Comment choisir son système de cache fichier ?

Si votre application est un logiciel Open Source, il est fort probable que ce sujet ait déjà été traité. Pour WordPress, il existe des plugins de cache fichier. Voici un billet qui réalise un benchmark de différents plugin de gestion de cache pour wordpress. L’objectif est de vous montrer par l’exemple, l’impact d’un cache et d’utiliser une bibliothèque PHP existante ou pas, pour améliorer les performances de votre application PHP.

Principe de fonctionnement d’un cache fichier PHP

La mise en place du système de cache fichier n’aura de sens que pour des sites dynamiques. Une application dynamique aura besoin de piocher des informations dans une base de données et de les manipuler pour construire la page HTML. Si vous avez un site web uniquement en HTML (pages statiques), ce billet n’est pas fait pour vous :). Le schéma ci-dessous montre les différents flux que nous pouvons trouver lors de la construction de la page HTML.

Principe de fonctionnement d'un cache fichier

Principe de fonctionnement d'un cache fichier

L’objectif du cache fichier est d’enregistrer une copie de la page html qui vient d’être générée par le script PHP (flux en orange sur le schéma). Lorsqu’une deuxième requête demande au serveur la même ressource (flux vert sur le schéma), cette dernière a déjà été générée et mise en copie par le flux orange. Le mécanisme de cache consiste donc à retourner cette page directement au navigateur en évitant tout le mécanisme de génération.

Mise en oeuvre et benchmark du système de cache fichier

Le principe de mise en oeuvre est très simple :

  • étape 1 : écrire un script PHP qui va manipuler une chaine de caractères. Il n’ y aura pas d’accès à une base de données pour simplifier la chose,
  • étape 2 : faire un premier benchmark,
  • étape 3 : écrire le mécanisme de cache fichier pour retourner le contenu du fichier lors de la prochaine demande,
  • étape 4 : faire un benchmark et comparer./>li>

Le script PHP fait une boucle afin de remplir une variable avec du texte. Nous faisons une manipulation de tableaux afin de charger le script et retournons une visualisation de ces données.

<?php
## Initialisation de la variable contenant le texte manipulé
$txt = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ';
//boucle
for ($t=0; $t<10; $ii++)
{
    $txt .= $txt;
}
//traitements
$temp = asort( explode(‘ ’,$txt));
$fin = array_keys($temp,‘dolor’);
//visualisation
$html = ‘’;
foreach($fin as $clef=>$values) {
	$html .= $clef . ‘--’ . $values . ‘<br>’;
}
echo $html;
?>

Nous réalisons le benchmark à partir de la commande ab suivante : ab -n1000 -c20 http://www.test.local/index.php
Après plusieurs tests, nous obtenons une moyenne de 160 requêtes par seconde. Le résultat du benchmark va dépendre de la puissance de votre machine de test. Ne vous focalisez pas sur le résultat. Seul un gain significatif est important à obtenir ! Pour cela mettons en place notre gestion de cache maison qui va créer un fichier « cache.html ».

<?php
## utilisation du cache si il existe et si il est toujours valide
if(file_exists(‘cache.html’) && ( (time() - 60) < filemtime(‘cache.html’)) {
	include ‘cache.html’;
	exit();
}

## Il n’ y a pas de cache : on écoute le buffer de sortie
ob_start(); ?>

## Initialisation de la variable contenant le texte manipulé
$txt = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ';
//boucle
for ($t=0; $t<10; $ii++)
{
    $txt .= $txt;
}
//traitement
$temp = asort( explode(‘ ’,$txt));
$fin = array_keys($temp,‘dolor’);
//visualisation
$html = ‘’;
foreach($fin as $clef=>$values) {
	$html .= $clef . ‘--’ . $values . ‘<br>’;
}
echo $html;

## on va écrire dans le fichier de cache
$fp = fopen('./cache.html', 'w');
fwrite($fp, ob_get_contents());
fclose($fp); 

## on retourne au navigateur le flux de sortie
ob_end_flush();
?>

Nous recommençons le benchmark avec la même commande à savoir : ab -n1000 -c20 http://www.test.local/index.php
Après l’exécution de plusieurs tests, nous obtenons une moyenne de 1200 requêtes par seconde.

Système de cache fichier : une réponse pour améliorer les performances de son application

Nous avons mis en évidence l’impact positif d’un système de cache fichier sur les performances d’une application web. Vous avez certainement remarqué au travers de l’exemple, que la mise en place d’un cache fichier va susciter certaines difficultés pour des projets existants.

Un code hétéroclite où la séparation des concepts métiers n’est pas respectée rend l’opération d’intégration d’un cache très délicate. Certains framework embarquent des mécanismes de cache mais nécessite une très bonne maîtrise de ces derniers. Nous allons découvrir la librairie «cache_lite» qui offre de nombreuses possibilités et va vous permettre de faire une intégration en douceur.

« Cache_lite » va vous permettre de tirer parti du cache fichier PHP à plusieurs niveaux :

  • fichiers, flux de sorti,
  • fonctions, objets,
  • tableaux, requête SQL etc..

Cache Lite : une librairie de cache fichier PHP performante

Cache_lite est une bibliothèque distribuée au sein de PEAR. Pour installer la librairie, plusieurs solutions :

  • « pear install Cache_Lite » dans votre invite de commande,
  • récupérer le tarball, décompressez et positionner le tout dans un répertoire accessible à votre environnement d’exécution web. Attention, «cache_lite» a une dépendance avec la gestion des erreurs de PEAR.

La base avec Cache Lite

La documentation de cache_lite est très bien faîte et je vous recommande de la parcourir. Aussi, nous allons reprendre notre exemple ci-dessus avec l’utilisation de cache_lite.

<?php

##inclusion de la librairie
require_once('Cache/Lite.php');

//options pour la définition du cache
$options = array(
    'cacheDir' => '/mon_rep_de_cache/',
    'lifeTime' => 3600
);
//définition d’un id qui permettra de retrouver le contenu caché
$id = 'cache';

//on instancie l’objet cache_lite
$Cache_Lite = new Cache_Lite($options);

//Est-ce que le cache existe ? pour l’id donné
if ($data = $Cache_Lite->get($id)) {
	echo $data;
} else {
	$txt = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ';
	//boucle
	for ($t=0; $t<10; $ii++)
	{
    	$txt .= $txt;
	}
	//traitement
	$temp = asort( explode(‘ ’,$txt));
	$fin = array_keys($temp,‘dolor’);
	$html = ‘’;

	foreach($fin as $clef=>$values) {
		$html .= $clef . ‘--’ . $values . ‘<br>’;
	}

    $Cache_Lite->save($html,$id);
	echo $html;
}

?>

La structure est beaucoup plus propre et peut être utilisé dans un bootstraping. Si vous utilisez un bootstraping et un contrôleur de dialogue capable de décortiquer un appel REST, vous pouvez utiliser ce mécanisme pour la gestion des ID du cache. REST est un format d’url unique puisqu’il indique une ressource cible.
Faisons un benchmark suite à cette intégration avec la même commande ab : ab -n1000 -c20 http://www.test.local/index.php
Après plusieurs tests, nous avons une moyenne de 1100 requêtes par seconde. Nous avons une perte de performance qui est due à l’utilisation de la librairie Cache lite. Cette petite perte de performance est largement compensée par ses apports techniques et la simplicité d’intégration et d’adaptation au sein de vos contraintes projets.

Cacher des blocs ou des requêtes SQL

La qualité du code, l’application elle-même, les accès à un backoffice nécessitent de pouvoir mettre en cache des blocs de contenu ou des résultats SQL (Moteur de recherche). Cache lite permet en fonction de votre code, de cacher des portions de code voir même des portions de flux html si vous utilisez le « echo » tout au long de votre implémentation.
Retrouvez des exemples d’utilisation dans la documentation de cache lite.

Conclusion

La compréhension du fonctionnement d’un système de cache fichier est la première étape avant de découvrir les autres possibilités qui vont s’offrir à vous. Je vous invite à bien comprendre le fonctionnement de Cache lite qui reste à ce jour, une très bonne bibliothèque de gestion de cache fichier PHP. Si votre application PHP est une solution Open Source, des plugins de gestion de cache existent. Analysez les, afin de choisir le plus performant ou implémentez votre propre plugin de cache.

La mise en place d’un système de cache fichier permet une amélioration significative des performances de votre application. Dans le cas d’une activité en perpétuelle évolution, la gestion du cache ne peut plus se résumer à cette simple mise en oeuvre que nous venons d’expliquer.

Une évolution significative du trafic va vous obliger à migrer sur de l’hébergement dédié voire sur une architecture. La gestion du cache devient alors un projet à part entière et fait parti intégrante des Road-Map. Les questions suivantes vont donc se poser :

  • peut-on tout cacher ?
  • doit-on tout cacher ?
  • peut-on et doit-on utiliser plusieurs systèmes de cache ?
  • comment invalider le cache ou quelle est la meilleure stratégie d’invalidation ?

Autant de questions qui seront abordées dans le prochain billet : « caching avancé : stratégie d’optimisation« .

5 réflexions au sujet de « Système de cache fichier PHP »

  1. Bonjour,

    Très bon article. Merci
    En fait il y a une erreur dans votre script. $txt n’est pas un tableau

    J’ai fait comme ceci pour que ça marche
    //traitement
    $temp = explode(" ",$txt);
    asort($temp);
    $fin = array_keys($temp,"dolor");

  2. Pourtant dans le script, je fais bien :
    $temp = asort( explode(‘ ’,$txt));
    exlpode => retourne un array
    $fin = array_keys($temp,‘dolor’);
    Je vais retester le script à l’occasion pour bien vérifier

    merci encore de votre commentaire !

  3. J’ai implémenté mon propre système de Cache PHP, pour mon site.
    Simplement, il a fallu trouver a chaque page, un ID unique. J’ai écrit le nom du fichier de cache de cette maniere là:
    cache_

    Ca tourne niquel !
    Merci !

    • Bonjour et merci de votre commentaire. J’ai tardé pour vous répondre mais je suis pas mal pris en ce moment. Pouvez vous détailler ce que vous avez fait et pourquoi pas partager le code.

  4. Hello,

    Une idée pour avoir un id unique par page est de faire un md5 de l’url en cours (avec ou sans les paramètres GET selon votre site),

    Ex :
    $url = http:// ».$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
    $id = md5(trim((string)$url));

    Adrien

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>