Optimiser Joomla! (Memcached et divers)

Niveau : débutant

Joomla! est un CMS (Content Management System) crée en 2005, et qui se répand progressivement. Il est aujourd'hui le 3e CMS Open Source, derrière Drupal et WordPress.
Sa souplesse et sa modularité font qu'il est tout autant adapté pour les sites web corporate, les sites promotionnels, les blogs, et mêmes les sites marchands.
Bien sûr, plus un framework est modulaire, et plus il est exigeant au niveau ressources, comme toute plateforme dynamique.
En tant qu'administrateur, vous aurez donc à héberger des sites Joomla!, un jour ou l'autre.
Dans cet article, j'explique brièvement son installation, ainsi que les "surprises" au niveau de son optimisation (Memcached ou autres) que j'ai eu avec la dernière version stable, la 3.2.1.
Tout ne fonctionne pas "out of the box", et je n'estime pas que Joomla! peut être mis en production, sans quelques optimisations.

Dans un article précédent, j'avais expliqué à quoi servait Memcached, comment il pouvait améliorer les performances de votre plateforme d'hébergement web, son architecture, et comment stocker les sessions PHP sur cette plateforme "in memory", distribuée.
Introduction à Memcached

Maintenant, nous allons l'interfacer avec Joomla!, et je prendrai comme exemple le site www.scalabilite.org, puisqu'il tourne sur ce CMS.

Conditions initiales

Nous avons un serveur web dédié, 192.168.0.60, et un serveur mysql séparé, 192.168.0.70.
En fait, ce sont sont des clusters, marchant en haute disponibilité ...
Mais pour vous, le fonctionnement des services HTTP et MySQL est totalement transparent, j'expliquerai leur fonctionnement dans un prochain article.
Les fichiers web sont stockés sur un filer NFS, le 192.168.0.3, mais de la même façon, c'est invisible pour le système, puisqu'un point de montage réseau est vu comme local par les logiciels.
J'ai monté mon partage NFS sur le répertoire /nfs/wwwcommon/scalabilite, et c'est le DocumentRoot que j'ai déclaré sur Apache.

Vous remarquerez que mon Apache tourne sur le port 81, pour des raisons sur lesquelles je ne m'étendrai pas pour le moment.
Veuillez noter que les noms de domaine accentués (autorisés par l'AFNIC depuis mai 2012) s'expriment via leur codage IDN, ou encore "punycode", dans la plupart des logiciels, que ça soit Apache, Varnish, ou même Joomla!
Sur votre navigateur, cette URL sera bien affichée comme www.scalabilite.org, il n'y a pas d’inquiétude à avoir.
J'ai aussi un certain nombre de directives de sécurité, sur lesquelles je suis plus ou moins libéral, selon les exigences du framework PHP.

<VirtualHost *:81>
        ServerAdmin Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.
        ServerName www.xn--scalabilit-k7a.fr
        ServerAlias xn--scalabilit-k7a.fr
        ServerAlias www.scalabilite.org
        ServerAlias scalabilite.org
        DocumentRoot /nfs/wwwcommon/scalabilite
        <Directory />
        # Mode parano #
                Options -Indexes -Includes -FollowSymLinks -MultiViews
        # Autorisation des fichiers .htaccess #
                AllowOverride All

                <LimitExcept GET POST>
                    deny from all
                </LimitExcept>
        </Directory>
        php_value Safe_Mode ON
        RewriteEngine On

        php_flag register_globals 0
        RewriteCond %{REQUEST_METHOD}  ^TRACE
        RewriteRule .* - [F]

        ErrorLog /var/log/apache2/error-scalabilite.log
        LogLevel warn
        CustomLog /var/log/apache2/access-scalabilite.log vhost_combined
</VirtualHost>

Il faut aussi noter que j'ai un postfix qui tourne sur le port smtp, pour relayer les mails.

Le serveur Memcached, quant à lui, est accessible via l'ip 192.168.0.81.
Il est dédié, comme les autres serveurs.
Je lui ai alloué 1GO de RAM, et il écoute en réseau.

Pour résumer, nous avons donc quatre serveurs dédiés, le web sur 192.168.0.60, le MySQL sur 192.168.0.70, les fichiers sont servis en NFS depuis le 192.168.0.3, et les sessions PHP ainsi que le cache de Joomla! seront stockées dans le  Memcached en 192.168.0.81.

Installation de Joomla!

Il vous faut maintenant télécharger la dernière version (francophone) de Joomla!, que vous trouverez sur www.joomla.fr.
Si vous avez le choix, pour un nouveau site, je vous conseille la 3.X, puisque les versions 2.X sont vouées à devenir obsolètes.
Il faut décompresser les fichiers, et les envoyer sur le serveur web.
Dans mon cas, dans le répertoire /nfs/wwwcommon/scalabilite.

Lorsque vous appellerez votre site web pour la première fois, une page vous guidera à travers l'installation.
Le logiciel vous indiquera les incompatibilités PHP et modules manquants, si vous en avez.
Pour le serveur MySQL, il faut indiquer l'ip, 192.168.0.70 dans mon cas.
Le logiciel créera alors la base correspondante, pour moi scalabilite, s'il en a les droits.

Surtout, si l'installation vous pose des questions sur le cache, ne pas l'activer !
Pour le moment, nous stockerons les sessions dans la base de données (option par défaut)

A la fin de l'installation, votre site est prêt à l'emploi, et vous pouvez en vérifier la configuration, via le fichier configuration.php.
Vous devriez obtenir quelque chose de ce type :

<?php
class JConfig {
        public $offline = '0';
        public $offline_message = 'Ce site est en maintenance.<br /> Merci de revenir ultérieurement.';
        public $display_offline_message = '1';
        public $offline_image = '';
        public $sitename = 'Scalabilité';
        public $editor = 'tinymce';
        public $captcha = '0';
        public $list_limit = '20';
        public $access = '1';
        public $debug = '0';
        public $debug_lang = '0';
        public $dbtype = 'mysqli';
        public $host = '192.168.0.70';
        public $user = 'scalabilite';
        public $password = '!!!youwillneverguess!!!';
        public $db = 'scalabilite';
        public $dbprefix = 'zzmbl_';
        public $live_site = '';
        public $secret = 'XOXOXOXOXO';
        public $gzip = '1';
        public $error_reporting = 'default';
        public $helpurl = 'http://help.joomla.fr/3/index.php?option=com_help&keyref=Help{major}{minor}:{keyref}';
        public $ftp_host = '';
        public $ftp_port = '';
        public $ftp_user = '';
        public $ftp_pass = '';
        public $ftp_root = '';
        public $ftp_enable = '0';
        public $offset = 'Europe/Paris';
        public $mailonline = '1';
        public $mailer = 'smtp';
        public $mailfrom = 'Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.';
        public $fromname = 'Milosz SZOT @ Scalabilité';
        public $sendmail = '/usr/sbin/sendmail';
        public $smtpauth = '0';
        public $smtpuser = '';
        public $smtppass = '';
        public $smtphost = 'localhost';
        public $smtpsecure = 'none';
        public $smtpport = '25';
        public $caching = '0';
        public $MetaDesc = 'Un blog qui parle de Linux, de serveurs web, de haute disponibilité, et de virtualisation, à destination des administrateurs et ingénieurs système.';
        public $MetaKeys = 'scalabilité, haute disponibilité, virtualisation, administrateur, ingénieur, système';
        public $MetaTitle = '1';
        public $MetaAuthor = '1';
        public $MetaVersion = '0';
        public $robots = '';
        public $sef = '1';
        public $sef_rewrite = '1';
        public $sef_suffix = '0';
        public $unicodeslugs = '1';
        public $feed_limit = '100';
        public $log_path = '/nfs/wwwcommon/scalabilite/logs';
        public $tmp_path = '/nfs/wwwcommon/scalabilite/tmp';
        public $lifetime = '60';
        public $session_handler = 'database';
        public $MetaRights = '';
        public $sitename_pagetitles = '1';
        public $force_ssl = '0';
        public $frontediting = '1';
        public $feed_email = 'site';
        public $cookie_domain = '';
        public $cookie_path = '';
        public $asset_id = '1';
}

Pour le moment, c'est une configuration banale, à part que j'ai indiqué que je voulais que le $mailer soit smtp, alors que la valeur par défaut est mail : Joomla! fait appel au Postfix local, au lieu de la fonction mail() de PHP, que je méprise au plus haut point ^_^

Tunings Memcached

Lorsque j'ai essayé pour la première fois d'activer Memcached dans mon Joomla!, j'ai eu le droit à une erreur 500 - internal server error, sur l'intégralité du site.
De mémoire, il faut passer les paramètres dans un ordre particulier : si dans l'interface graphique d'installation , nous définissons le stockage des sessions sur Memcached, alors que l'on n'a pas configuré le caching du site, la variable qui définit le serveur memcache ne sera pas positionnée correctement, alors qu'elle est censée être partagée par les deux fonctionnalités.
Qu'à cela ne tienne, nous avons la possibilité d'écrire directement sur le fichier configuration.php !

J'ai donc ajouté (ou modifié) les variables dans cet ordre :
        public $caching = '2';
        public $cache_handler = 'memcache';
        public $memcache_server_host = '192.168.0.81';
        public $memcache_server_port = '11211';
        public $cachetime = '60';
        public $session_handler = 'memcache';
        public $memcache_persist = '0';
        public $memcache_compress = '0';

Je n'ai pas activé la compression de Memcached.
Parce qu'elle utiliserait plus de processeur et qu'au final, les requêtes auraient un peu plus de latence.
Memcached ayant avant tout comme objectif d’accélérer le traitement des pages, je ne ferai de compromis sur ses performances que quand la mémoire sera saturée.

Pour faire fonctionner plusieurs sites Joomla! sur une même grappe Memcached, il faut que chacun d'entre eux ait une variable $secret différente, sinon, des problèmes de sessions apparaitront.
Cette variable est utilisée par le contrôleur Memcached de Joomla! pour différencier les instances.

Il me reste encore à tester Joomla! sur plusieurs serveurs Memcached, distribués, mais je vous avoue que je n'ai pas encore eu cette possibilité, je manque de place dans mon lab, et il n'est pas question de le faire en production ;-)

Le fichier .htaccess

Il y a quelques règles de réécriture d'url dans le fichier .htaccess livré avec Joomla!.
Mais très vite, je me suis aperçu que les "best practices" web étaient aux abonnés absents.
En effet, lorsque je mets en ligne un nouveau site, je le passe dans la moulinette Google PageSpeed Insights, qui me permet de détecter les oublis grossiers.
Page Speed Insights

Les éléments textuels n'étaient pas compressés (deflate), et le cache navigateur n'était pas exploité pour les éléments statiques du site (expires).
Pour un site tel que Scalabilité, qui n'a pas vocation à accueillir des millions de visiteurs, cela n'a pas beaucoup d'importance.

Toutefois, à l'échelle d'une plateforme d'hébergement web, cela peut avoir un impact important :
- côté plateforme, nous pouvons économiser beaucoup de bande passante (et donc réduire nos coûts ou servir plus de visiteurs)
- les reverse-proxies cache, comme Varnish, se servent des valeurs de cache transmises par les serveurs web pour déterminer s'ils doivent "déranger" les serveurs web
- côté visiteurs, avec la prolifération des smartphones et des tablettes, toute économie sur le chargement des pages est bonne à prendre pour améliorer l'affichage des pages, surtout que les liaisons sans-fil ne sont pas toujours terribles ...

J'ai donc ajouté les règles suivantes à mon fichier .htaccess :

SetOutputFilter DEFLATE

<IfModule mod_expires.c>
  FileETag MTime Size
  AddOutputFilterByType DEFLATE text/plain text/html text/xml text/css text/javascript application/xml application/xhtml+xml application/rss+xml application/javascript application/x-javascript
  ExpiresActive On
  ExpiresDefault "access plus 1 seconds"
  ExpiresByType text/html "access plus 600 seconds"
  ExpiresByType text/css "access plus 604800 seconds"
  ExpiresByType application/xhtml+xml "access plus 600 seconds"
  ExpiresByType image/jpeg "access plus 2592000 seconds"
  ExpiresByType image/png "access plus 2592000 seconds"
  ExpiresByType image/gif "access plus 2592000 seconds"
  ExpiresByType text/javascript "access plus 604800 seconds"
  ExpiresByType application/javascript "access plus 604800 seconds"
  ExpiresByType application/x-javascript "access plus 604800 seconds"
  ExpiresByType image/x-icon "access plus 604800 seconds"
</IfModule>

Il faut bien entendu que sur vos Apache, les modules deflate et expires soient activés.

Conclusion

J'ai maintenant une plateforme Joomla! configurée "aux petits oignons".
Je sais gérer un site Joomla! à fort trafic, ou tout simplement déployer des instances du logiciel dans le cadre d'une plateforme mutualisée, avec des sites prêts à l'emploi.

Enfin ... presque ! Il me manque un dernier élément, qui fera prochaine l'objet d'un article : Varnish, un reverse-proxy qui fait office de cache HTTP pour les éléments statiques, à la différence de Memcached, qui sert de cache applicatif.

Partager l'article

Submit to FacebookSubmit to Google PlusSubmit to Twitter

Ajouter un Commentaire


A propos de l'auteur

Milosz SZOTMilosz SZOT est ingénieur systèmes & réseaux spécialisé dans Linux et l'hébergement de sites web à fort trafic.

En savoir plus