Tag Archives

3 Articles
Optimiser Zend Partie 2 : mémoire

Optimiser Zend Partie 2 : mémoire

Aujourd’hui nous allons voir la suite de l’optimisation Zend. Je sais, ça fait un moment que je devais le faire mais là j’ai le temps.

Pour ce tutoriel je suis sur un unbuntu 10.04 LTS avec PHP5.3.2 et avec le cache APC activé. Les résultats que vous verrez povienne de tests sur mon site perso en temps réel en local afin que vous vous fassiez une idée sur la consommation d’un site vers la fin de son développement de la taille du mien.

Nous allons donc voir aujourd’hui la consommation mémoire de chacune de vos pages ou plutôt de vos actions, via un fichier de log généré par Zend. Ce log est généré par une fonction intégrée au bootstrap de votre projet. Je vais vous enseigner comment le mettre en place.

Nous verrons à la fin la charge mémoire du site avec les require_once laissés dans la library Zend (voir poste précédant) puis en les enlevant pour voir s’il y a une réelle différence.

La taille d’allocation mémoire calcule juste la mémoire utilisée par PHP dans le chargement des classes, données et l’exécution de vos scripts. Elle n’a rien à voir avec les images qui composent votre site.

Pour commencer, nous avons besoin du plugin Zend effectuant toute la partie traitement:

class App_Controller_Plugin_MemoryPeakUsageLog extends Zend_Controller_Plugin_Abstract
{
    protected $_log = null;

    public function __construct(Zend_Log $log)
    {
        $this->_log = $log;
    }

    public function dispatchLoopShutdown()
    {
        //récupère l'usage de mémoire utilisé réellement par PHP
        $peakUsage = memory_get_peak_usage(true);
        //on récupère l'url de la page en cours
        $url = $this->getRequest()->getRequestUri();
        //on stoque tout sa dans notre fichier de log avec le statut info
        $this->_log->info($peakUsage . ' bytes ' . $url);
    }
}

Et pour finir voici la fonction à ajouter dans notre bootstrap afin d’exécuter ce plugin automatiquement pour chaque page:

protected function _initEnableMemoryUsageLogging()
{
    //initialisation d'un fichier de log
    //il doit exister pour être utilisé.
    $writer = new Zend_Log_Writer_Stream(
    APPLICATION_PATH . '/logs/memory_usage');
    //création d'un log rattaché à notre fichier précédemment iinitialisé
    $log = new Zend_Log($writer);
    //on appelle un plugin s'occupant de tout ce traitement
    $plugin = new App_Controller_Plugin_MemoryPeakUsageLog($log);

    /**
     * Si vous mettez votre plugins avant tous les autres, ils seront
     * pris en compte dans le calcul de mémoire.
     */
    $frontController = $this->getResource('frontController');
    //on enregistre le plugin
    $frontController->registerPlugin($plugin);
}

Normalement, en allant sur la page d’index de votre page, le fichier memory_usage devrait avoir la ligne suivante:

2010-05-24T16:07:23+02:00 INFO (6): 20971520 bytes /throrinstudio/</code> 

La valeur affichée en bytes équivaut à 20 Mo environ. Si vous refaites un chargement de cette page, la mémoire a diminuée, ceci grâce au cache APC de PHP:

2010-05-24T16:08:33+02:00 INFO (6): 6291456 bytes /throrinstudio/

La valeur ici équivaut à 6,2 Mo environ. Maintenant nous enlevons les require_once de la library Zend et nous effectuons un autre test (il y a encore le cache APC) :

2010-05-24T17:09:27+02:00 INFO (6): 6029312 bytes /throrinstudio/

Ceci équivaut à 6 Mo. La différence n’est pas énorme mais mon site utilise peu de classes Zend. Si vous prenez un gros site intégrant Zend_AMF, Zend_DB et d’autres aussi gourmands, vous aurez une plus grande différence qu’ici. Idem si vous n’utilisez pas le cache APC. En purgeant le cache, j’arrive à la valeur suivante lors du premier chargement:

2010-05-24T17:09:16+02:00 INFO (6): 19922944 bytes /throrinstudio/

Ici, ça nous fait 19 Mo. Si nous regardons ce résultat par rapport au premier, nous arrivons à une différence de 1 Mo d’utilisation mémoire.

En conclusion, cette partie n’est pas vraiment une optimisation. Elle sert surtout à voir l’utilisation mémoire de votre site. Vous pouvez constater la différence d’utilisation mémoire avec et sans le cache APC. Cette différence est tout de même énorme (14 Mo dans l’exemple).

Installation de PHP 5.2 dotdeb sur Ubuntu

Installation de PHP 5.2 dotdeb sur Ubuntu

by Throrïn 0 Comments

Aujourd’hui je vais vous faire résoudre un problème récurent que j’ai eu sur mes serveurs. L’installation de PHP 5.2.13 sur Ubuntu en utilisant les paquets dotdeb.

Pourquoi passer par ces paquets ? Et bien c’est plus simple que de compiler soit même PHP et ça évite d’oublier des dépendances. Le problème des paquets dotdeb c’est qu’ils sont prévus pour Debian or, Ubuntu utilise des Library avec quelquefois des noms différents. Je vais donc vous expliquer pas à pas l’installation de cette version.

Cette procédure ne marche plus à partir d’Ubuntu 10.04 LTS. D’un car les dépendances ne sont plus disponibles, de deux car une version plus récente de PHP est disponible.

Tout d’abord, il vous faut ajouter les sources APT pour installer tout un serveur LAMP @dotdeb dans le fichier /etc/apt/sources.list:

deb http://packages.dotdeb.org stable all 
deb-src http://packages.dotdeb.org stable all

Ensuite, il vous faudra installer apache :

sudo aptitude install apache2 apache2-mpm-prefork apache2-prefork-dev apache2-utils apache2.2-common

Ensuite, si nécessaire, installez le serveur MySQL qui va bien:

sudo aptitude install mysql-client mysql-client-5.1 mysql-common mysql-server mysql-server-5.1 mysql-server-core-5.1

Pour finir nous allons installer toutes les Library requises pour l’installation de PHP.

sudo aptitude install libtidy-dev curl libcurl4-openssl-dev libcurl3 libcurl3-gnutls zlib1g zlib1g-dev libxslt1-dev libzip-dev libzip1 libxml2 libsnmp-base libsnmp15 libxml2-dev libsnmp-dev libjpeg62 libjpeg62-dev libpng12-0 libpng12-dev zlib1g zlib1g-dev libfreetype6 libfreetype6-dev libbz2-dev libxpm4-dev libmcrypt-dev libmcrypt4

Voilà. Malgré tout, il nous faut installer 3 Library introuvables par aptitude mais nécessaires à l’installation des paquets dotdeb. Nous récupérons les fichiers nécessaires avec l’utilitaire wget.

32bits:

wget http://us.archive.ubuntu.com/ubuntu/pool/main/k/krb5/libkrb53_1.6.dfsg.4~beta1-5ubuntu2_i386.deb
wget http://us.archive.ubuntu.com/ubuntu/pool/main/i/icu/libicu38_3.8-6ubuntu0.2_i386.deb
wget http://mirrors.kernel.org/ubuntu/pool/main/libt/libtool/libltdl3_1.5.26-1ubuntu1_i386.deb

64bits:

wget http://us.archive.ubuntu.com/ubuntu/pool/main/k/krb5/libkrb53_1.6.dfsg.4~beta1-5ubuntu2_amd64.deb
wget us.archive.ubuntu.com/ubuntu/pool/main/i/icu/libicu38_3.8-6ubuntu0.2_amd64.deb
wget http://mirrors.kernel.org/ubuntu/pool/main/libt/libtool/libltdl3_1.5.26-1ubuntu1_amd64.deb

Et nous installons les différents fichiers :

32bits:

sudo dpkg -i libkrb53_1.6.dfsg.4~beta1-5ubuntu2_i386.deb
sudo dpkg -i libicu38_3.8-6ubuntu0.2_i386.deb
sudo dpkg -i libltdl3_1.5.26-1ubuntu1_i386.deb

64bits:

sudo dpkg -i libkrb53_1.6.dfsg.4~beta1-5ubuntu2_amd64.deb
sudo dpkg -i libicu38_3.8-6ubuntu0.2_amd64.deb
sudo dpkg -i libltdl3_1.5.26-1ubuntu1_amd64.deb

Et voilà, il n’y a plus qu’à installer PHP :

sudo apt-get update
sudo apt-get install php5

Rajoutez les extensions utiles :

sudo apt-get install php5-apc php5-curl php5-gd php5-mcrypt php5-mhash php-pear php5-mysql

Voilà, maintenant vous avez un serveur LAMP fonctionnel avec PHP 5.2.13.

Optimiser Zend – Partie 1

Cela fait un moment que je ne vous ai pas refait de tutoriaux pour le Framework Zend. Aujourd’hui je vous propose une adaptation d’un tutoriel en anglais que l’on m’avait fait parvenir et qui m’a grandement aidé (malheureusement, il n’est plus sur la toile).

Vous savez comme moi que l’un des points faibles de Zend Framework, c’est la performance, il est beaucoup plus lent que du PHP objet de base du fait de la majeur partie des classes qui sont chargées lors du lancement d’une page. Je vais donc réaliser ce tutoriel en plusieurs parties.

Aujourd’hui, je vais juste vous expliquer comment diminuer les chargements inutiles et redéfinir le fichier d’amorçage (le fameux index.php). Vous vous souvenez tous comment est composé le fichier index.php ? Et bien voici un petit rappel pour ceux qui ne savent pas :
/**
* Fichier index.php permettant de lancer le bootstrap
*
*/

//Définition du chemin vers le dossier application
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH',
realpath(dirname(__FILE__) . '/../application'));

//Définition de la variable de d'application (utile pour les fichiers de configuration
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV',
(getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
: 'production'));

//Partie permettant d'inclure les différentes librairies
//du dossier library (en théorie).
//Nécessite un complément côté bootstrap.
set_include_path(implode(PATH_SEPARATOR, array(
dirname(dirname(__FILE__)) . '/library',
get_include_path(),
)));

/** Zend_Application */
require_once 'Zend/Application.php';

// Créer l'application, le bootstrap et démarre
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configurations/app.ini'
);
$application->bootstrap()
->run();

Nous allons juste ajouter une petite partie permettant d’inclure plus rapidement les classes de Zend en repassant par Zend_Autoloader et nous redéfinirons sa méthode d’inclusion. Voici donc le nouveau index.php qui vous parlera mieux que mes explications :
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH',
realpath(dirname(__FILE__) . '/../application'));

// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV',
(getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
: 'production'));

// Typically, you will also want to add your library/ directory
// to the include_path, particularly if it contains your ZF install
set_include_path(implode(PATH_SEPARATOR, array(
dirname(dirname(__FILE__)) . '/library',
get_include_path(),
)));

//redéfinition de l'autoloader par défaut afin d'optimiser le chargement
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->setDefaultAutoloader(create_function('$class',
"include str_replace('_', '/', \$class) . '.php';"
));

/** Zend_Application */
//require_once 'Zend/Application.php';

// Create application, bootstrap, and run
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configurations/app.ini'
);
$application->bootstrap()
->run();

Cette partie ne suffit pas, pour gagner encore du temps, je vous invite à suivre le conseil donné par l’équipe Zend en fin de documentation, à savoir, supprimer tous les require_once inutiles de la bibliothèque Zend. (je vous invite aussi à les enlever de vos controller, formulaires, …).

En effet, pour chaque require_once, le serveur va effectuer des accès disque et c’est ces accès disques qui ralentissent le serveur. La méthode est donc de les enlever et ensuite, notre redéfinition faite dans le index.php prendra le relais, elle effectuera tardivement le chargement de tous les fichiers nécessaires afin d’optimiser le chzrgement de nos classes. La documentation Zend explique mieux que moi cette partie:

Le chargement tardif (« lazy loading ») est une technique d’optimisation conçue pour repousser l’opération coûteuse de chargement d’une classe jusqu’au dernier moment possible – c’est-à-dire lors de l’instanciation d’un objet de cette classe, ou lors de l’utilisation d’une constante de classe ou d’une propriété statique. PHP supporte tout ceci via l’autoloading (ou « chargement automatique »), ce qui vous permet de définir un ou plusieurs callbacks à exécuter dans le but de faire correspondre un nom de classe à un fichier.

Cependant, la plupart des avantages que vous pourrez retirer de l’autoloading sont diminués si le code de votre librairie exécute toujours des appels à require_once – ce qui est précisément le cas de Zend Framework. La question est donc : comment éliminer ces déclarations require_once dans le but de maximiser les performances de l’autoloader.

Pour ce faire, il ne vous suffit que d’exécuter cette commande sous Linux (je rajouterai celle sous Windows et FreeBSD quand je les aurais retrouvé) :
% cd chemin/vers/la/librarie/ZendFramework
% find . -name '*.php' -not -wholename '*/Loader/Autoloader.php' \
-not -wholename '*/Application.php' -print0 | \
xargs -0 sed --regexp-extended --in-place 's/(require_once)/\/\/ \1/g'

Pour finir, nous définissons une nouvelle fonction dans notre Bootstrap principal afin que lui aussi tire parti de ces changements :
public static function autoload($class)
{
include str_replace('_', '/', $class) . '.php';
return $class;
}

Voilà, après ces quelques modifications, votre site devrait se charger un poil plus vite et consommer moins de mémoires.

Dans la seconde partie, je vous expliquerai comment créer une méthode qui mesure la charge mémoire de chacune de vos pages. Si vous avez des questions, des remarques, des critiques ou même des corrections, n’hésitez pas à me les faire parvenir.