02
Mar 11

Réflexion générale sur l’optimisation d’hébergement de sites eZ Publish

eZ PublishPréambule:

Je ne suis pas développeur… mais sysadmin, et connais donc très peu les aspects bonnes pratiques de code eZ, etc.

 

J’ai du mal à comprendre qu’un site internet * nécessite des serveurs « sur dimensionnés », avec plus de 4 Go de RAM (que dis-je… 2 Go !!!), big processeurs etc.

(*) Je ne parle pas bien entendu de sites avec de forts enjeux / fréquentations (commerce, presse etc.)

Nombre de projets (pas forcément eZ) qui, dés le départ, sont hébergés sur des machines de guerre… semblent fonctionner très bien… jusqu’au fameux pic de fréquentation.
Et la, « problème »: c’est pas facile de rajouter autant de RAM que de visiteurs, et la maintenance corrective de l’application n’est soit pas possible, soit trop chère, soit les 2 🙂

 

Ainsi, je suis persuadé qu’il est bon de définir une limite saine des ressources allouées à un serveur en fonction des besoins, ici: un site internet.

Du coup, cela « force » indirectement mes collaborateurs (dev) à faire du site propre et optimisé 🙂

(oui, je suis l’ennemi du dev)

 

En cas de montée en charge, liée à une hausse de fréquentation (et non pas à des applications folles :D), je suis plus adepte du scale out (ajout de serveurs).

 

Objet de l’article

Ça fait maintenant quelques années que je travaille sur de l’hébergement eZ Publish, LE CMS de référence (dixit mes collaborateurs) qui peut s’avérer parfois… « ressourcophage ».

 

J’ai pu tester et mettre en oeuvre plusieurs types d’architecture, de la VM seule à la plateforme hautement disponible, mêlant du Squid, HA/LB, et autres réplications d’annuaires et bases de données.

 

L’idée de ce post est de lancer / reprendre quelques idées pour continuer à optimiser les plateformes d’hébergement eZ Publish, et relancer des petits Labs.
Donc, ne vous attendez pas à trouver LA solution miracle, mais juste des retours d’expériences et une vision parcellaire du sujet.

 

Les solutions abordées ici sont considérées comme « stables », étant déjà déployées sur de nombreux projets (eZ ou pas), et documentées sur Internet.

Constat

Même s’il est vrai que, depuis la version 4.x d’eZ (PHP5), il y a eu de nettes améliorations coté performance, il n’en demeure pas moins que l’on ne peut pas héberger cette application sur n’importe quel environnement.

 

Coté « logiciel »:

Suivre les pré requis de cette dernière n’est pas toujours possible selon l’hébergeur, voir même la distribution Linux, notamment si l’on ne souhaite pas mettre les mains dans le cambouis et compiler les sources.

 

Certaines distributions (ex RHEL)  ne mettent pas à disposition depuis leur dépôt, les Packages nécessaires au bon fonctionnement et à l’optimisation de l’application (ex APC pour RHEL 5.6, mbstring pour RHEL 6 => Mea Culpa…).

 

Mais il ne faut pas se leurrer:  si on veut une solution qui va plus loin que la moyenne, il ne faut pas s’attendre à pouvoir l’installer et l’exploiter dans n’importe quelle condition.

Mais bon, ce n’est pas l’objet de ce post 😉

 

Ce n’est donc pas sur ce point que je m’attarderai;

Installer une pile LAMP en suivant à la lettre des pré requis doit être dans les cordes d’un hébergeur.

 

Coté « matériel »:

(Attention, je parle de consommation de ressources, pas de matériel en tant que tel.)


Je me suis aperçu que, dans bien des cas, les problèmes de performance (hors problème de conception) étaient liés aux accès disques, et à la sollicitation du serveur MySql.

Par exemple, le simple fait de migrer l’application vers un serveur (ou une VM) avec un stockage de qualité (disques SAS 10/15k ou SAN) diminue la charge du système, et notamment le nombre de processus Apache qui s’empilent…

 

Malheureusement, dans la tête de beaucoup de personnes, un « bon » serveur est une machine blindée de RAM, avec un CPU de dernière génération. Mais on oublie souvent la performance du contrôleur et des disques durs, ce qui est une erreur pour un contexte eZ Publish.

 

Dans un environnement multi frontaux, la nécessité d’un filer partagé (répertoires cache / medias …) implique bien souvent l’utilisation d’un serveur NFS, qui est loin d’être la meilleure solution pour avoir des I/O performants (sauf  couche NetApp $$$).

 

Je pense que la problématique du « filer » partagé pour eZ mérite un Lab à part entière… pour avoir testé plusieurs solutions différentes dans le passé (NAS / SAN OCFS2…). De nouvelles fonctions  ont vu le jour, notamment concernant le fameux « cache ». Je n’aborderai donc pas ce sujet ici, d’autant plus qu’il me faudra du support « dev eZ » 😉

 

Donc, à mon sens, voici les axes d’optimisation vis à vis des ressources qu’un site eZ consomme majoritairement, et qui sont source de goulot d’étrangement:

  • Serveur(s) MySql (de la bonne gros requête)
  • Accès disque (I/O) (écritre / lecture – fichiers de cache)
  • RAM code PHP / SQL => faux problèmes => harceler développeurs.

 

Je cherche donc à limiter et optimiser l’utilisation de ces ressources, en dehors du tuning de chaque composant de la pile LAMP et de l’infrastructure d’hébergement (réseau, stockage, système…)

 

Pour cela, il existe des solutions simples et efficaces que je vais présenter rapidement ci-dessous.

Varnish + Apache/Lighttpd + Memcached

Dans un contexte multi frontaux.

 

+ Reverse Proxy frontal Varnish

Rien de transcendant; Beaucoup l’ont fait, le font et le feront.

 

Le premier objectif est de mettre en cache tout ou une partie du site afin d’alléger les serveurs « eZ » : Apache / PHP


Le second est de faire servir les différents médias (pas encore en cache, ou ceux qui ne doivent pas y être) par des serveurs Lighttpd, le reste (eZ Publish) étant traité par Apache.


Vieux de la vieille, j’ai toujours été très partisan d’un bon Squid pour cela. Mais la mode et les pratiques de mes confrères me poussent donc à expérimenter un peu plus loin cet outil,  ayant déjà fait mumuse avec, à titre personnel.

 

L’intégration des ESI est également un pas de plus dans l’optimisation des temps de réponse d’un site, même s’il comporte des données en front, qui doivent être mise à jour fréquemment. (ex: mettre en cache toute la page d’accueil, sauf un block contenant les dernières actualités, etc.).

 

Mais cela concerne plus la fabrication du site, que Varnish lui même (Squid sachant le faire également ;p )

 

Pour la HA, un LoadBalancer en amont de type HaProxy / LVS… et ça roule.

 

Le ReverseProxy permet donc de:

  • Limiter le nombre de requête aux serveurs front Apache (et donc des i/o et SQL) grâce à la mise en cache des pages
  • Dispatcher, en fonction des contenus appelés, le trafic vers des frontaux « spécialisés » (voir ce qui suit)

 

+ Frontaux web par fonction: séparer le traitement PHP et les médias

 

L’idée est, vous l’avez compris, de tirer profit des performances de Lighttpd pour servir des fichiers statiques, et laisser apache traiter le strict nécessaire: PHP / eZ Publish.

 

+ Mettre en cache les sessions

Depuis les dernières versions d’eZ Publish, il est possible de dire comment stocker les sessions:

  • en base de données (historique semble-t-il)
  • en fonction du php.ini (depuis peu, par défaut, sur disque)

When this setting is left empty, « eZSessionHandlerPHP » is used which basically leaves session handling to PHP so that PHP session handlers like « files » (default) can be used, as defined by php.ini « session.save_handler ».

Note: Depuis les versions récentes, il n’y a plus de session créée pour les accès anonymes (bien!)

La seconde option apporte un gain de performance non négligeable. Ne plus stocker les sessions dans la BDD allège bien évidemment le serveur SQL.

 

Mais Quid du fonctionnement avec des multi frontaux dans ce cas?

Qui dit multi frontaux, dit filer partagé (ie NFS).

 

On a donc plusieurs possibilités… du plus sexy au plus sale!

  • Demander à un Load Balancer de faire du « sticky session »

D’après mes expériences, cela implique que, lorsqu’une session est ouverte, l’utilisateur connecté reste sur le même frontal, et n’est donc plus « load balancé ». Du coup, plus de problème de perte de session… mais plus de « sécurité » !

En effet, si pendant ce temps le serveur frontal tombe, session perdue…

  • Stocker les sessions sur le filer partagé

La voila la solution sale :p

Et voila la ptite solution qui permettrait de répondre au besoin.

 

Dans ma tête, il était nécessaire de gérer cela au niveau de l’application.

Mais en fait, il est possible de forcer la configuration dans le php.ini de chaque frontaux:

session.save_handler = memcache
session.save_handler = memcachesession.save_path = « tcp://srv_memcache1:11211?persistent=1&weight=1&timeout=1&retry_interval=15,tcp://srv_memcache2:11211?persistent=1&weight=1&timeout=1&retry_interval=15″

Comme on peut le voir ci-dessus, il est possible de spécifier plusieurs serveurs MemCache, ce qui répondrait du coup, à ce que nous voulons:

  • pas de SPOF sur les sessions en cas de service HS d’un des serveurs MemCache
  • amélioration des performances (exit SQL et I/O sur le filer pour les sessions)

Tests « rapides » de performance avec ou sans Varnish en front

Site eZ Publish utilisé:

Un des sites « modèle » disponibles par l’assistant d’installation

 

Avec activation des « caches » sur la racine:

[HTTPHeaderSettings]
CustomHeader=enabled
Cache-Control[]
Cache-Control[/]=
Pragma[]Pragma[/]=
Expires[]Expires[/]=1200

PS: Bon, si je dis des bêtises, ne m’en veuillez pas… c’est pas mon truc la conf eZ 😀

 

1 seule machine « low cost » (ovh)

avec des accès disques moyens (voir mauvais).

CPU: Celeron D/215/220
RAM: 2 Go

root@srv1:~# hdparm -tT /dev/sda2

/dev/sda2:
Timing cached reads: 1166 MB in 2.00 seconds = 582.88 MB/sec
Timing buffered disk reads: 188 MB in 3.01 seconds = 62.38 MB/sec

root@srv1:~# hdparm -tT /dev/sda2

/dev/sda2:
Timing cached reads: 1094 MB in 2.00 seconds = 546.69 MB/sec
Timing buffered disk reads: 192 MB in 3.02 seconds = 63.61 MB/sec

A titre de comparaison, sur mes VMs, on a un « Timing cached reads »  de:

  • entre 4 et 5 GB/sec sur la recette
  • entre 6 à 8 GB/sec sur la prod

 

Pile LAMP + Varnish + Lighttpd + Memcache

Note: J’ai pas respecté à la lettre les versions des pré requis eZ, ayant voulu installer les dernières versions Apache / PHP

 

Tout est installé sur un même serveur:

  • Varnish :80
  • Apache: 8080
  • Lighttpd: 8081

 

Debian 6 – 64 bits

root@srv1:~# apachectl -v
Server version: Apache/2.2.17-MartY (Unix)
Server built: Feb 27 2011 19:15:31

root@srv1:~# php -v
PHP 5.2.17 (cli) (built: Feb 27 2011 21:01:47)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2010 Zend Technologies
+ APC 3.1.2
+ memcache-2.2.6

root@srv1:~# mysql -V
mysql Ver 14.12 Distrib 5.0.51a, for unknown-linux-gnu (x86_64)

root@srv1:~# lighttpd -v
lighttpd/1.4.28 – a light and fast webserve

root@srv1:~# varnishd -V
varnishd (varnish-2.1.5 SVN )
Copyright (c) 2006-2009 Linpro AS / Verdens Gang AS

root@srv1:~# memcached -help
memcached 1.4.5
(…)

Les tests

Aspirer le site

Le 1er test consiste à lancer un wget (aspirer le site entier en fait), et de voir le temps passé (time).

time wget -r -k -np –user-agent=vilain http://ezpublish.nicolas-martinez.info

 

On ne peut pas dire que ce soit un bench digne de ce nom, mais juste un bon indicateur.
J’ai gardé les meilleurs résultats (3 exécutions par cas)

 

Avec le cache eZ

Sans Varnish

real 2m36.881s
user 0m0.536s
sys 0m0.760s

Avec Varnish

real 1m25.183s
user 0m0.660s
sys 0m0.756s

Après vidage du cache eZ (php bin/php/ezcache.php –clear-all)

Sans Varnish

real 4m14.779s
user 0m0.780s
sys 0m0.908s

Avec Varnish

real 3m18.433s
user 0m0.672s
sys 0m0.740s

J’ai graphé l’utilisation de ressources avec une installation basique de munin, mais les tests sont trop proches et le serveur ne fait pas grand chose… donc bon.

C’est pas très propre, et il faudrait le faire pour MySql etc; C’est prévu 🙂

 

Je mets les I/Os histoire de mettre un graph 🙂

En gros, les « pics » correspondent à la désactivation de Varnish en front.

 

Apache Bench

Le second, lui plus classique, un Apache Bench:

  • -n Nombre total de requêtes envoyées
  • -c Nombre de requêtes envoyées en parallèle

Sur celui-ci, il s’agit plus de tester la montée en charge de la machine.

 

Sans Varnish

ab -c 100 -n 5000 http://ezpublish.nicolas-martinez.info:8080/ »

Requests per second: 39.66 [#/sec]

load average: 11.3

Avec Varnish

ab -c 100 -n 5000 http://ezpublish.nicolas-martinez.info:80/ »

Requests per second: 46.75 [#/sec]

load average: 0.23

Conclusion

Avec l’implémentation de ce type de mécanismes simples à mettre en œuvre, on peut assez rapidement limiter la consommation de ressources et optimiser les temps de réponse de sites eZ Publish. Bien entendu, ce petit Lab ne se « copie / colle » pas sur tout projet eZ, il faut tenir compte des contraintes de l’application. (ex: pas possible de mettre toute la page en cache)

 

Cela ne remplace pas, bien entendu, l’optimisation de l’application, et le tunning système propre à chaque environnement.


  • Bertrand Dunogier

    Excellent! Pas l’énergie pour des commentaires techniques, mais c’est super d’avoir le point de vue d’un bon gros sysadmin! Merci bien 🙂

  • Merci pour cette analyse intéressante Nicolas.

    A titre informatif, Varnish est utilisé sur share.ez.no, Load avg autour de 0.2, une seule machine, développement front-end effectivement à « penser Varnish » pour tout ce qui est personnalisé (pas mal d’Ajax, ou de tricks JS), pour une fréquentation d’environ 7000PVs/jour (~1300 Visiteurs).

    Cheers !

  • @Bertrand Dommage, ca manque cruellement de retours sur ce qui se fait 🙂
    Et j’aime bien avoir le point de vue d’un bon gros Geek (Dev ??)

    @Nicolas Oui, Arnaud nous a dit ca lors de son « escapade » dans le sud chez nous ;p Quand j’aurai un peu plus de temps, je ferai quand même un comparatif avec Squid, rien que pour embêter Gandbox qui me harcelait avec Varnish sans cesse 😉

  • Huy

    Excellent article.
    As tu deja essaye de remplacer completement Apache par Lighthttpd ou Nginx et PHP-fpm?

  • Merci 🙂
    Pour des sites eZ Publish, non.

    Sinon, pour des sites PHP « lambda », Lighttpd + fastcgi fonctionne très bien; je l’utilise pour des serveurs de « médias » qui hébergent des scripts php pour le traitement des images (ex création miniatures, etc.).

    Je n’ai jamais testé Nginx / php-fpm.
    En lisant rapidement les releases de php-fpm, la 1ere version stable date de 2007… année depuis laquelle je me suis focalisé sur l’hébergement eZ, qui nécessite Apache + php en module 😉
    Mais je vais y jetter un oeil, merci bien!

    Tu as de bons retours de ton coté?

  • squid utilise un modèle de thread, varnish utilise un moteur événementiel. Avec php-fpm, apache n’est plus un prérequis, nginx et lighttpd sont bien plus prévisible et performant. Stocker des sessions sur disque est juste criminel, memcache est maintenant un prérequis pour tout serveur web, et encore plus quand on en a plusieurs. ab est un outil vieillissant, amha, siege est aussi simple et plus réaliste. Je rale, mais cet article est complet et interessant.

  • Merci Mathieu pour ce retour. C’est dans un contexte eZ Publish?
    Car ici, je ne traite pas du LAMP lambda 😉

    Pour les sessions, eZ met par défaut tout en BDD, ce qui est une bonne chose pour du multi-front (garder la session ouverte sur du LB).
    Mais niveau perf… ça peut faire mal sur des pics de fréquentation.

    Sur disque, bah c’est quand même plus « performant » qu’en base. Mais je suis complètement ok avec toi, il y a mieux 🙂 (d’ou mon mini speech à ce sujet)

    Concernant Varnish / Squid… ça joue quand même pas (encore) dans la même cour. Ok, Varnish donne de très bonnes perf, on le voit bien ici sur ces tests basiques (je te l’accorde).

    Mais qu’en est-il de la scalabilité ?

    Est-il possible de répartir le cache Varnish sur « n » serveurs frontaux? Si c’est possible avec Vanirsh, bingo.

    Sinon, c’est la que Squid, avec son concept de hiérarchie de cache amène une plus-value non négligeable sur des sites à fort trafic.
    Car répartir la charge sur « n » frontaux applicatifs, c’est bien.

    Le faire également sur des Reverse Proxy, qui savent eux même aller chercher sur un MISS, le cache sur le « parent » et non pas sur les fronts web, c’est sexy et surtout performant 🙂

    Je ne parle même pas des possibilités de PRA/PCA, gestion des flux réseaux etc. :p

  • Je me permets d’ajouter quelques idées:

    – toujours bien vérifier le IO causé par le serveur mysql. J’ai l’impression que bon nombre de bdd dédiées à eZ font tout simplement piétiner le site à cause des table temporaires stockées sur le disque. Soit mieux parametrer son my.cnf, soit utiliser un ramdisk pour ces tables?

    – la config des headers http de expiration pour les ressources statiques est un fondamental souvent oublié. C’est obligatoire si on veut que le reverse proxy marche, mais ca devrait être tout aussi bien obligatoire sans reverse proxy

    – go go Nginx – meme sans php-pfm c’est un serveur excellent

    – en eZP 4.5, on peut finalement obtenir une homepage à 0 requêtes sql, et qui n’ouvre même pas de connexion à la bdd (on peut obtenir de meme pour toutes les pages de contenus, si on utilise les url ‘système’ et avec une peite modif de ini)

  • Merci pour ces compléments.

    Pour MySql, j’opte pour du TMPFS sur le tmpdir 😉

  • Je suis sur que Squid a des fonctions qui tue, mais voir l’approche de Varnish peut être rafraichissant. Pour moi la comparaison est valable : apache=>nginx/lighty, squid=>varnish. Je suis curieux de connaitre le volume nécessaire pour saturer un varnish, et du coups nécessiter une grappe. Il y a quelques temps, j’ai vu passer la tactique d’un site de rencontre allemand. Nginx va piocher directement dans memcache du contenu que lui pousse du PHP. Trés spécifique, mais ça donne des idées sur ce que peut faire les serveurs asynchrones.

  • Oui tout a fait; Squid peut être vu comme un vieux soft… tout comme Apache.

    Sans parler de « saturation », mais juste de Failover / Load Balancing.
    Un serveur qui lâche, ca arrive (matos par exemple).

    Comment ca se passe si je repartis la charge sur « n » Varnish?
    Y a t il une synchro des caches, ou faut il attendre que chacun d’entre eux ait reçu le trafic?

    Attention, je suis séduit par Varnish, mais sur des aspects d’architectures (système & réseau), je ne m’y retrouve pas encore.

    Si je dois en faire une « fonction » (pile proxy) pour une plateforme, il me faut le sécuriser en tant qu’entité.
    Pour l’instant, en vulgarisant, je l’envisage presque comme un « composant » complémentaire à Apache (ou autre service http)… un peu comme APC pour PHP 😀

    Nginx, je connais sans plus, juste sur ma veille techno.
    Il va falloir remédier à cela 😉

  • [mode troll]
    Comme ça par hasard, tu ne veut pas faire le même billet mais pour de l’hébergement Drupal ?
    [/mode troll]

  • Ça reste du LAMP, et je ne suis pas sectaire ;p

    Qui sait… peut être que france.fr en aura besoin 😀

  • Quelqu’un a comparé Nginx, Lighttpd, Varnish, G-WAN at Apache Traffic Server, en performances et en usage CPU / mémoire:

    http://nbonvin.wordpress.com/2011/03/24/serving-small-static-files-which-server-to-use/

    Apparemment, les serveurs de cache (Varnish et Apache TS) ne sont pas si bien placés…

  • … très intéressant, merci.