dimanche 3 mars 2013

Mise en cache

La mise en place d’une gestion de cache est un bon moyen d’économiser des ressources machines, idéal pour améliorer le confort de navigation des visiteurs.

On peut définir le cache comme un mécanisme dont le but est d’économiser des ressources en supprimant les traitements redondants. Typiquement, le cache permet d’éviter de générer une page dynamique plusieurs fois, dans la mesure ou celle-ci ne change pas d’un appel à l’autre.

Mais on peut aller plus loin avec le cache : tout d’abord, en mettant en cache non pas une page, mais une partie de page (cache partiel). Enfin, on retrouve le cache sur plusieurs niveaux : le plus bas niveau concerne la mise en cache du code compilé de PHP et le plus haut, la mise en cache des pages. Entre les deux, il est possible de mettre en cache des retours de fonctions, des blocs d’information ou des objets.

Exercice 1 : Installation d'APC

1) Vérifiez la présence du paquet php-apc sur votre serveur.

2) Installez le paquet php-apc si celui ci n'est pas encore présent.

3) Trouvez et copiez le fichier apc.php dans /www/htdocs/sitezend_avance/html/

4) Affichez la page de monitoring apc.php


Exercice 2

1) Créez le fichier /www/library/class/ZendCache.php et ajoutez y le code PHP de l'annexe 1.


Exercice 3

1) Chargez la class ZendCache créée dans l'exercice 2 dans le bootstrap.


Exerice 4

1) Créez un script PHP et vérifiez que le cache fonctionne correctement.


Exercice 5

1) Mettez en cache l'opcode de votre application


Annexe 1

class Library_Class_ZendCache
{
    private static $_cache = null;
    private static $_lifetime = 3600;
    private static $_cacheDir = null;

    private static function init() {

        if (self::$_cache === null) 
        {
            $frontendOptions = array('automatic_serialization' => true, 'lifetime' => self::$_lifetime);
            $backendOptions = array('cache_dir', self::$_cacheDir);
   
            try {
                if (extension_loaded('APC'))
                {
                    self::$_cache = Zend_Cache::factory('Core', 'APC', $frontendOptions, array());
                }
                else
                {
                    self::$_cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions);
                }
            }
            catch (Zend_Cache_Exception $e)
            {
                    throw new Zend_Exception($e);
            }

            if (!self::$_cache) 
            {
                throw new Zend_Exception("No cache backend available.");
            }
   
        }

    }

    public static function setup($lifetime, $filesCachePath = null) {

        if (self::$_cache !== null)
        {
            throw new Zend_Exception("Cache already used.");
        }

        self::$_lifetime = (integer) $lifetime;

        if ($filesCachePath !== null)
        {
            self::$_cacheDir = realpath($filesCachePath);
        }

    }

    public static function set($data, $key) {

        self::init();
        return self::$_cache->save($data, $key);

    }

    public static function get($key) {

        self::init();
        return self::$_cache->load($key);
  
    }

    public static function clean($key = null) {

        self::init();

        if ($key === null)
        {
            return self::$_cache->clean();
        }

        return self::$_cache->remove($key);

    }

    public static function getCacheInstance() {

        if (is_null(self::$_cache))
        {
            throw new Zend_Exception("Cache not set yet.");
        }

        return self::$_cache;

    }
}

Correction de l'exercice 1

Pour commencer, on vérifie que le paquet php-apc n'est pas déjà installé sur notre serveur. On éxécute pour cela la commande suivante :

$ apt-cache policy php-apc

Si on obtient le résultat suivant c'est que APC n'est pas encore installé :

Pour l'installer c'est simple :

$ apt-get install php-apc

Pour vérifier que l'installation c'est bien déroulée, rendez-vous dans le phpinfo et vérifiez la présence d'APC :

Lors de l'installation d'APC, un script de monitoring a été fourni. Nous allons le trouver et le copier dans notre dossier de travail.

Pour trouver un fichier à partir de son nom (apc.php) sur debian, nous allons utiliser la commande suivante :

$ find / -name apc.php* 2>/dev/null

Ce qui devrait nous retourner le résultat suivant :

Le fichier qui nous intéresse est /usr/src/APC-3.1.8/apc.php

La commande cp va nous permettre de le copier dans notre répertoire de travail.

cp /usr/src/APC-3.1.8/apc.php /www/htdocs/sitezend_avance/html/

On test en chargeant apc.php depuis notre navigateur :


Correction de l'exercice 2

On commence par créer notre dossier class dans library :

$ mkdir /www/library/class/

Puis on créé le fichier ZendCache.php

$ nano /www/library/class/ZendCache.php

Et on y colle notre class :

On enregistre et on quitte


Correction de l'exercice 3

Maintenant nous devons indiquer à notre application de charger la class que nous venons de créer.

Pour cela on fait appel à notre bootstrap dans lequel nous allons ajouter un objet Zend_Loader_Autoloader_Resource comme vu précédement pour ajouter un modèle.

$ nano /www/htdocs/sitezend_avance/application/Bootstrap.php

Dans lequel nous allons ajouter la fonction suivante à la suite.

protected function _initCache () {
 
 $resourceLoader = new Zend_Loader_Autoloader_Resource(array(
  'basePath'  => '/www/library',
  'namespace' => 'Library',
 ));

 $resourceLoader->addResourceType('class', 'class/', 'Class');
 
}

Correction de l'exercice 4

Passons maintenant aux tests. Nous allons faire nos tests dans le contrôleur index.

$ nano /www/htdocs/sitezend_avance/application/controllers/IndexController.php

Et dans la méthode indexAction() on ajoute :

public function indexAction() {
 
 $reservations = Library_Class_ZendCache::get('reservations');
  
 if (!$reservations)
 {
  $reservations = 'Chaine contenant les réservation'.' date: '.time();
   
  Library_Class_ZendCache::set($reservations, 'reservations');
  
  echo 'Inséré dans le cache : '.$reservations;
 }
 else
 {
  echo $reservations;
 }
  
}

Lors du premier affichage vous devriez avoir :

Le cache reservation n'est pas disponible, donc il met notre chaine en cache sous le nom réservation.

Puis lors du second rechargement :

Le cache est maintenant disponible il choisi donc de l'afficher.


Correction de l'exercice 5

Il faut savoir qu'actuellement, lorsque vous chargez un script PHP, les étapes suivantes font s’exécuter :

  • Chargement du script PHP depuis le disque dur
  • Compilation du script PHP (op-code)
  • Exécution de la compilation par PHP
  • Affichage du résultat

Le cache APC va nous permettre de mettre directement la compilation de nos pages PHP en mémoire RAM, ainsi au lieu de charger nos pages depuis le disque dur et de devoir les interpréter à chaque fois, il chargera des version compilé depuis la mémoire RAM ce qui nous fera gagner un temps précieux.

Pour commencer il nous faut connaitre la taille de notre application (Zend Framework compris), pour nous il s'agit du /www/. Pour cela on utilise la commande du :

$ du -sh /www/

L'option -s permet d'afficher que le total (et non la taille de chaque sous-dossier). L'option -h permet d'afficher un résultat lisible par humain (en non pas en kio)

On obtient un résultat de 42M. On va multiplier ce résultat par 1,5 car l'op-code est environ 1,5 fois plus dense que le code PHP brut. Donc 42 x 1,5 = 63.

Indiquons à APC qu'il peut utiliser jusqu'à 63 Mio de mémoire pour mettre en cache les fichiers.

Pour savoir où se trouve le fichier de configuration, nous allons afficher notre phpinfo()

Maintenant que nous savons où se trouve notre fichier de configuration il ne nous reste plus qu'à le modifier :

$ nano /etc/php5/apache2/conf.d/apc.ini

Et on rajoute apc.shm_size = 63 dans notre fichier.

On enregistre et on quitte.

On redémarre Apache pour prendre en compte les modifications :

$ /etc/init.d/apache2 restart

On revient sur la page de monitoring :

Et on peut apercevoir que la nouvelle taille du cache a été prise en compte.

Maintenant nous allons mettre notre application en cache :

Pour commencer on va créer le fichier /www/htdocs/sitezend_avance/html/compil_apc.php et y coller le code suivant :

class MyFilterIterator extends FilterIterator
{
 public function accept() {
  
  if (substr($this->current(), - 3) == 'php')
  {
   return $this->current();
  }
  
 }
}

$rdi = new RecursiveDirectoryIterator('/www/');
$rii = new RecursiveIteratorIterator($rdi, RecursiveIteratorIterator::LEAVES_ONLY);

apc_clear_cache();

foreach (new MyFilterIterator($rii) as $file)
{
 if (apc_compile_file($file->getPathname()))
 {
  echo "OK : apc_compile_file(".$file.")\n";
 }
 else
 {
  echo "ERROR : apc_compile_file(".$file.")\n";
 }
}

Et on l'éxécute :

A priori tout c'est déroulé correctement. Revenons au monitoring APC :

On peut s'apercevoir que le cache est maintenant rempli et qu'il contient 2 527 fichiers.

Vérifiez de temps à autres qu'il reste de la mémoire pour APC et que le taux de hit (appel caché) et supérieur au taux de miss (appel non caché).

Aucun commentaire:

Enregistrer un commentaire