English version is available here: Optimize you StatusNet instance for better performances and features
Dans l'épisode précédent
Cette publication constitue le second épisode de mon "feuilleton de l'été" consacré à StatusNet. Vous pouvez consulter les précédents là:
- Part 1: Installer sa propre instance StatusNet avec PHP-FPM et Nginx
- Part 2: Optimiser les performances et les fonctionnalités de son instance StatusNet
- Part 3: Une extension pour optimiser les performances de son instance StatusNet
Je ferai appel, sans entrer dans les détails, à des éléments de configuration déjà abordés:
- Nginx: Configuration d'hôtes virtuels avec support automatique des sous-domaines, du SSL et de l'authentification sous GNU/Debian Linux version 2
- PHP-FPM, le serveur d'application par PHP
Néanmoins, les éléments purement liés à la configuration de StatusNet sont applicables, même si vous utilisez un autre serveur web.
Introduction
Si vous avez installé votre propre instance StatusNet, vous avez dû vous rendre compte... que c'est lent.
Par défaut, StatusNet va réaliser toutes les actions par l'intermédiaire de la connexion de votre navigateur. Par exemple, abonnements, publications, etc... se font de manière synchrone.
Cela signifie que vous risquez, si ce n'est déjà fait, d'être confrontés à des timeout sur vos requêtes, générant une erreur du serveur et un état instable de votre instance (abonnement incomplet, publication pas ou partiellement propagée, etc...). Bref, il faut remédier au problème.
Fort heureusement, StatusNet vous permet de paramétrer très finement son comportement. Petit tour d'horizon.
Faire le tri dans les plugins
StatusNet a, lors de son installation, activé un certain nombre de plugins. Malheureusement, ce point n'est à ma connaissance pas (ou alors mal) documenté. Après quelque recherches, vous tombez sur //identi.ca/main/version. Et comme le logiciel est le même, vous disposez de cette même page sur votre instance.
Par défaut donc, un certain nombre de plugins sont activés. Pour ma part, je ne les trouve pas tous utiles ou pertinents. Qu'à cela ne tienne, on peut les désactiver dans le fichier de configuration:
En fonction des plugins, vous gagnerez soit en requêtes externes (ex: GeoNames) soit en temps de calcul (ex: RSSCloud) soit en temps d'affichage de la page web (ex: Mapstraction). Dans tous les cas, vous êtes gagnant :)
Utiliser les files d'attentes asynchrones
Comme je le soulignais en introduction, le comportement par défaut de StatusNet consiste à gérer les tâches de manière synchrone. Simple, mais pas particulièrement efficace.
Par exemple, si vous devez diffuser un message à différents abonnés répartis sur d'autres instances StatusNet, il y a toutes les chances du monde pour que le boulot ne soit fait qu'à moitié lorsque la connexion sera coupée par l'expiration du temps d'exécution du script PHP.
Évidemment, rien ne vous empêche d'augmenter le temps maximum d'exécution des requêtes PHP, mais cela risque fort de causer d'autres problèmes en cascade, comme une saturation du serveur web. La vraie solution, la seule pérenne en tout cas, consiste à activer le gestionnaire de file d'attente intégré de manière à permettre l'exécution de certaines tâches de manière asynchrone.
Inconvénient de cette solution: il faut alors gérer un service, écrit en PHP, qu'il faudra démarrer à l'allumage du serveur et redémarrer au besoin ce qui signifie avoir un accès en ligne de commande au serveur. Ce seul point disqualifie la plupart des offres d'hébergement mutualisé pour mettre en place sa propre instance StatusNet.
L'activation des files d'attente se fait de manière relativement simple:
MySQL sera utilisé en tant que backend par défaut. Pour d'évidentes raisons liées à la sécurité, nous spécifions un utilisateur particulier, et non privilégié, pour faire fonctionner tout ça, en l'occurence l'utilisateur que PHP-FPM utilise pour faire fonctionner StatusNet.
Vous pouvez alors démarrer le service. Dans la mesure où il faudra réaliser un changement d'ID utilisateur, il faut avoir les droits root pour pouvoir lancer le script:
Le script va d'abord lister les services pertinents compte tenu de la configuration de StatusNet et les démarrer les uns à la suite des autres. Par défaut il n'y en a qu'un: queuedaemon.php. Vous pouvez d'ailleurs le vérifier à la main:
Pour stopper les process, un autre script est disponible:
Pour paramétrer le démarrage de tout ça au boot, on peut ajouter la commande start dans le fichier /etc/rc.local:
À partir de maintenant, seuls les abonnements seront gérés de manière synchrone. La réception et l'envoi des messages s'effectuera, quant à elle, de manière asynchrone.
Accessoirement, le jour où, par exemple, identi.ca rencontre quelques soucis, le gestionnaire de file d'attente fera le boulot à votre place: il ré-essaiera de délivrer les messages éventuels tout seul comme un grand (le nombre d'essai maximum est fixé à 10 par défaut).
Utiliser les fonctionnalités de cache d'opcode
Un grand classique dans le monde PHP. Dans certains cas, PHP va, presque, prendre plus de temps pour analyser et compiler le code que pour l'exécuter.
Je ne sais pas si c'est exactement le cas ici, mais, clairement, l'utilisation de l'extension APC accélère votre instance. Alors, pas d'hésitation, on fait:
D'après mon expérience, un segment mémoire de 32M (configuration par défaut de l'extension PHP) suffit amplement pour StatusNet.
Attention toutefois à une chose: même avec PHP-FPM et des processus utilisant des uid/gid différents, le cache APC est partagé entre tous les processus. Normalement pas de soucis, mais c'est toujours bon à savoir.
Utiliser les fonctionnalités de cache de données
StatusNet supporte plusieurs systèmes de cache de données : APC, Memcache, Memcached, Xcache, ... Je n'en retiendrai que 2, les 2 que je connais le mieux: APC et Memcache
En fait, il est inutile d'utiliser les plugins APC et Memcache de StatusNet en même temps. Ils font exactement le même boulot: cacher des informations diverses, dont la configuration. En l'occurrence, le premier déclaré dans le fichier de configuration gagne.
La logique voudrait alors que l'on privilégie APC au détriment de Memcache car cela évite des connections TCP. Oui mais... le cache APC est propre à chaque processus. Cela signifie que les processus PHP-FPM vont utiliser un segment APC, et les services de file d'attente que l'on a activé au-dessus un autre.
Résultat: les caches vont être désynchronisés. Effet le plus visible: la timeline n'est plus rafraîchie, même si les nouveaux messages sont bien enregistrés dans le système. Génant.
Je préconise donc d'utiliser le plugin Memcache, qui sera partagé par le moteur StatusNet d'une part et par les services de file d'attente d'autre part.
Notez que StatusNet supporte aussi l'extension Memcached via le plugin éponyme.
Il ne reste plus qu'à activer le plugin Memcache dans le fichier de configuration StatusNet:
Bien entendu, il faut également, si ce n'est déjà fait, installer le serveur memcache:
Enfin, il faut redémarrer PHP-FPM de manière à prendre en compte les changements:
Vous devriez déjà sentir la différence... non ? Alors rajoutons-en une couche. Un plugin méconnu de StatusNet utilise encore un peu plus les fonctionnalités de cache: InProcessCache
Malheureusement, peu d'informations sont disponibles sur son fonctionnement, sauf à se plonger dans le code, ce que je vous laisse faire. Une information importante néanmoins:
Dont acte. La configuration devient:
Il existe encore d'autres plugins permettant la mise en cache des informations. Je vous laisse creuser ceux qui vous intéressent, ils sont tous dans le répertoire /var/www/apps/statusnet/docroot/plugins.
Attention cependant, certains ne cohabitent pas bien ensembles, notamment à cause des extensions PHP qui leurs sont nécessaires (exemple: APC et XCache).
Merci à Karlesnine qui m'a permis de piger comment fonctionnaient les plugins APC et Memcache :)
Checkschema m'a tué
Checkschema est bien l'une des fonctionnalités de StatusNet dont le paramétrage par défaut m'a le plus surpris. Il s'agit ni plus ni moins de vérifier la structure de la base de données.
Les plugins peuvent avoir besoin de créer une ou plusieurs tables spécifiques, et checkschema se revèle alors extrèmement pratique puisqu'il vérifie à votre place que le schéma de la base est conforme à la configuration. Merveilleux lorsque l'on découvre StatusNet.
Malheureusement, le paramétrage par défaut effectue cette vérification... à chaque requête HTTP. Une véritable catastrophe.
Vite, changeons cela:
Au passage, j'en ai profité pour changer la manière de se connecter à la base de données. Lorsque PHP et MySQL sont sur le même serveur, utilisez toujours les sockets de préférence à la connection TCP.
Une fois checkschema désactivé, n'oubliez pas de vérifier manuellement la structure de la base de données si vous changez la configuration. Pour cela, vous pouvez utiliser le script prévu à cet effet.
Je n'ai toujours pas compris pourquoi checkschema est paramétré de la sorte par défaut sans plus de précautions. Toujours est-il que c'est là que j'ai eu le plus gros gain de performances, en tout cas l'un des plus visibles :-/
Alléger l'interface web
Après avoir tenté d'optimiser le cœur du système, passons à l'interface utilisateur, en l'occurrence l'interface web.
Vous n'aurez pas grand contrôle sur la structure même des pages web. De plus, elles sont relativement complexes. Par exemple, la page de votre profil affiche les avatars de vos abonnements. Autant de connexions HTTP supplémentaires à réaliser pour les récupérer.
Il existe néanmoins une solution qui, à défaut d'être super efficace, améliore un peu les choses: changer le thème de l'interface pour un autre plus léger, et surtout choisir un domaine alternatif pour la diffusion des fichiers statiques.
Naturellement, il faut du coup configurer un hôte virtuel dédié. Pour quoi dédié ? Tout simplement car je désactive par défaut les journaux d'accès pour les ressources statiques, ce qui élimine les opérations d'entrées/sorties disque correspondantes:
Je vous laisse à titre d'exercice le soin de séparer les fichiers PHP des fichiers statiques. En effet, il n'est pas concevable de laisser les 2 hôtes virtuels utiliser la même arborescence, sauf à vouloir que votre fichier config.php soit librement accessible via l'hôte virtuel static.domain.tld.
Cette étape de l'optimisation aura été l'occasion de vous montrer jusqu'à quel point on peut configurer une instance StatusNet.
Désactiver le support des SMS
Destiné au départ à "copier" Twitter, StatusNet intègre lui aussi le support des SMS. On peut bien entendu le désactiver:
Une petite astuce dont la découverte m'a ravi tant les processus d'abonnements étaient devenus pénibles: il fallait à chaque fois décocher l'option SMS.
Comment faire pour trouver les options de configuration
Pas de secret, tout est dans le code :)
Plus sérieusement, il y a 2 fichiers que vous devez connaître. Le premier contient les valeurs de configuration par défaut que le système utilisera à moins qu'elles ne soient surchargées:
Le second, lui, vous donne toutes les options de configurations actives et leur valeur courante:
Cette commande est doublement indispensable: tout d'abord elle sera votre compagnon lors des soirées que vous passerez à hacker StatusNet. D'autre part, elle vous sera nécessaire si vous décidez de poser des questions sur le forum StatusNet. À conserver précieusement donc :)
Conclusion
Voici le fichier de configuration tel qu'il devrait être si vous avez appliqué toutes les recettes que j'ai détaillées:
Voilà, nous arrivons au terme du second épisode. La prochaine fois, petite récréation, nous verrons comment interconnecter StatusNet et Twitter et obtenir l'affichage des nouveaux messages en temps réel (ou presque).
Enjoy :)
Sources et références
StatusNet
- StatusNet
- //status.net/open-source/
- //status.net/wiki/
- Installation
- //status.net/wiki/Installation
- Getting started
- //status.net/wiki/Take_a_tour
- //status.net/wiki/NoticeSymbols
NGinx
- Official website
- //www.nginx.org/
- ////wiki.nginx.org/
PHP-FPM
- Official website
- //www.php-fpm.org
- //fr2.php.net/manual/en/install.fpm.php