Monitoring d'une installation PHP5-FPM

Comment superviser son serveur php5-fpm, quelles sont les métriques collectées ?

Il est un temps pas si lointain où il était difficile de savoir ce qui se passait sur ses serveurs web au niveau PHP. Tout était mélangé dans un processus Apache2 et savoir ce que PHP consomme comme mémoire, comme processus était chose quasi impossible.

C’est désormais beaucoup plus facile si vous utilisez un socle de serveurs web avec php5-fpm. Si ce n’est pas le cas, regardez si votre hébergeur supporte ce mode de fonctionnement de PHP. Si vous ête sur serveur dédié, n’attendez plus pour passer à php5-fpm ! Outre une meilleure visibilité côté PHP, vous aurez également de meilleures performances pour vos applications PHP.

Configuration de php5-fpm pour la supervision

php5-fpm expose, à l’instar de Nginx ou Apache2 ses statistiques, métriques internes sur une URL particulière qu’il reste à définir dans le fichier de configuration du pool; soit /etc/php5/fpm/pool.d/www.conf par défaut sur une Ubuntu.

;listen = 127.0.0.1:9000
listen = /var/run/php-fpm.sock

pm.status_path = /status

ping.path = /ping

Commenter/décommentez la ligne listen qui vous convient en fonction du fait que vous accédiez à votre installation php5-fpm via TCP ou socket.

Il faut ensuite configurer le serveur web en frontal de l’installation php5-fpm afin d’exposer ces valeurs au travers d’une URL. Cette configuration diffère en fonction du serveur. Voici la configuration pour les deux serveurs web les plus utilisés sur la toile - au moins d’après BuiltWith -.

Configuration avec Apache 2

configuration du fichier /etc/apache2/conf.d/php5-fpm.conf pour Apache2

<IfModule mod_fastcgi.c>
    AddHandler php5-fcgi .php
    Action php5-fcgi /php5-fcgi virtual
    Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi
    #FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -host 127.0.0.1:9000 -pass-header Authorization
    FastCGIExternalServer /usr/lib/cgi-bin/php5-fcgi -socket /var/run/php-fpm.sock
</IfModule>

Même remarque que précédemment concernant la directive FastCGIExternalServer.

et dans l’hôte virtuel par défaut par exemple, ajouter ce bloc :

<FilesMatch "^ping|status$">
    SetHandler php5-fcgi
</FilesMatch>

Il est bien sûr fortement conseillé de restreindre l’accès à ces URLs sur la boucle locale ou par IP afin que n’importe qui ne puisse pas accéder à ces informations.

Configuration avec Nginx

Si vous utilisez Nginx plutôt que Apache2 en frontal de votre installation php5-fpm, vous pouvez alors utiliser le bloc de configuration suivante :

location ~ ^/(status|ping)$ {
     access_log off;
     allow 127.0.0.1;
     allow 10.10.10.10#your-ip;
     deny all;
     include fastcgi_params;
     fastcgi_pass 127.0.0.1:9000;
}

Les métriques collectées

Les données accessibles à travers l’URL mise en place sont mises à jour en temps réel. Ce que vous voyez représente donc votre installation PHP au moment de l’interrogation.

Pour voir si cela fonctionne, utilisez par exemple curl http://localhost/status sur la ligne de commande. Si tout est correctement configuré, vous obtenez la sortie suivante :

pool:                 www
process manager:      dynamic
start time:           24/Mar/2014:13:16:10 +0100
start since:          2551
accepted conn:        7843
listen queue:         0
max listen queue:     0
listen queue len:     0
idle processes:       8
active processes:     2
total processes:      10
max active processes: 10
max children reached: 0

  • pool est le nom du pool au sens php5-fpm.
  • process manager dont la valeur est à static, dynamic ou ondemand.
  • start time est la date et l’heure à laquelle php5-fpm a été démarré.
  • start since est le nombre de secondes ecoulées depuis le dernier démarrage de php5-fpm.
  • accepted conn est le nombre de requêtes servies par le pool.
  • listen queue est le nombre de requêtes dans la queue des connections en attente.
  • max listen queue est le nombre maximale de requêtes dans la queue des connections en attente depuis le dernier démarrage.
  • listen queue len est la taille de la socket pour la queue des connections en attente.
  • idle processes est le nombre de processus en attente.
  • active processes est le nombre de processus actifs.
  • total processes est le nombre de processus total; soit en attente + actifs.
  • max active processes est le nombre maximal de processus actifs depuis le dernier démarrage.
  • max children reached est le nombre de fois où la limite de processus alloués a été atteinte.

Formats de sortie

Par défaut, la sortie est formatée en texte simple. En passant html, xml ou json dans la requête, vous obtenez le format de sortie correspondant. Ainsi curl http://127.0.0.1/status?json donne la sortie formatée JSON suivante :

{"pool":"www","process manager":"dynamic","start time":1395663370,"start since":2708,"accepted conn":8779,"listen queue":0,"max listen queue":0,"listen queue len":0,"idle processes":3,"active processes":26,"total processes":29,"max active processes":50,"max children reached":1}

Une valeur importante à noter dans cette sortie est le max children reached qui doit être à zéro sous peine de devoir refuser des requêtes par manque de processus enfants pour les accepter.

Métriques supplémentaires

Si vous en voulez plus, vous pouvez ajouter full à votre demande pour obtenir une sortie beaucoup plus détaillée. Ainsi, curl "http://127.0.0.1/status?json&full" donne la sortie suivante (tronquée car très longue) :

{"pool":"www","process manager":"dynamic","start time":1395663370,"start since":3898,"accepted conn":14567,"listen queue":0,"max listen queue":0,"listen queue len":0,"idle processes":9,"active processes":1,"total processes":10,"max active processes":50,"max children reached":1, "processes":[{"pid":7492,"state":"Idle","start time":1395666547,"start since":721,"requests":344,"request duration":165244,"request method":"GET","request uri":"/index.php","content length":0,"user":"-","script":"/var/www/index.php","last request cpu":78.67,"last request memory":45350912},{"pid":7481,"state":"Idle","start time":1395666411,"start since":857,"requests":420,"request duration":143462,"request method":"POST","request uri":"/index.php","content length":7356,"user":"-","script":"/var/www/index.php","last request cpu":97.59,"last request memory":46923776},{"pid":7482,"state":"Idle","start time":1395666426,"start since":842,"requests":411,"request duration":172243,"request method":"POST","request uri":"/index.php","content length":7584,"user":"-","script":"/var/www/index.php","last request cpu":92.89,"last request memory":46923776}]}

Les infos données sont celles-ci :

  • pid est le numéro d’identification du processus « PID ».
  • state est l’état du processus parmi Idle, Running
  • start time est la date et l’heure à laquelle le processus a été démarré.
  • start since est le nombre de secondes ecoulées depuis le démarrage du processus.
  • requests est le nombre de requêtes servies par le processus.
  • request duration est la durée en µs des requêtes.
  • request method est la méthode utilisée dans la requête (GET, POST, …).
  • request URI L’URI demandée avec la chaîne de caractères requêtée.
  • content length est la longueur de la requête (seulement avec POST).
  • user est l’utilisateur (PHP_AUTH_USER) ou - si non renseigné.
  • script est le script principal appelé ou - si non renseigné.
  • last request cpu est le pourcentage de CPU consommé par la dernière requête. Toujours à 0 si le processus est dans un état autre que Idle car ce calcul est fait quand la requête est traitée.
  • last request memory est la quantité de mémoire maximale utilisée par la dernière requête. Toujours à 0 sir le processus est dans un état autre que Idle car ce calcul est fait quand la requête est finie de traiter.

Voilà de quoi faire mine de rien, que ce soit pour correctement dimensionner votre installation PHP ou la monitorer. Reste à collecter ceci de façon automatique et à intervalles réguliers avec votre solution de supervision.

Collecte avec Collectd

Vu que l’URL de statut permet de formater la sortie en JSON, nous allons utiliser le plugin de Collectd cURL-JSON pour la parser. Le bénéfice supplémentaire d’utiliser Collectd est de pouvoir envoyer toutes ces métriques dans RRD ou mieux, Graphite, mais pas seulement…

Nous ajoutons ce bloc de configuration à Collectd. Il fait correspondre les libellés des métriques fournies par php5-fpm et les types gérés par Collectd.

LoadPlugin curl_json
<Plugin curl_json>
<URL "http://serveur_hostname_or_ip/status?json">
  Instance "www"
  <Key "accepted conn">
      Type "fpm_connections"
  </Key>
  <Key "listen queue">
      Type "fpm_queue"
  </Key>
  <Key "max listen queue">
      Type "fpm_queue_max"
  </Key>
  <Key "listen queue len">
      Type "fpm_queue_lenght"
  </Key>
    <Key "idle processes">
      Type "fpm_ps_idle"
  </Key>
  <Key "active processes">
      Type "fpm_ps_active"
  </Key>
  <Key "total processes">
      Type "fpm_ps_total"
  </Key>
    <Key "max active processes">
      Type "fpm_ps_active_max"
  </Key>
    <Key "max children reached">
      Type "fpm_child_max_reached"
  </Key>
</URL>
</Plugin>

Il faut encore définir les « types » de données collectées en le précisiant dans le fichier de Collectd types.db. Cela permet à Collectd de savoir comment définir une métrique (compteur, jauge…).

# types.db
fpm_connections         value:COUNTER:0:65535
fpm_queue               value:GAUGE:0:65535
fpm_queue_max           value:GAUGE:0:65535
fpm_queue_lenght        value:GAUGE:0:65535
fpm_ps_idle             value:GAUGE:0:65535
fpm_ps_active           value:GAUGE:0:65535
fpm_ps_active_max       value:GAUGE:0:65535
fpm_ps_total            value:GAUGE:0:65535
fpm_child_max_reached   value:GAUGE:0:65535

Il y a sûrement de la place pour faire mieux mais la base fournie devrait vous permettre d’améliorer tout ça. N’oubliez pas de partager vos résultats !

Graphe avec Grafana

Voilà en tout cas le résultat dans un graphe Grafana bien sûr.

Représentation des processus FPM dans Grafana
Représentation des processus FPM dans Grafana

Le nom des métriques est un peu « pourri » mais je n’ai pas trouvé de moyen pour le moment de renommer ces métriques avant injection dans Graphite. J’en suis arrivé à la conclusion que je ne pouvais rien y faire mais si quelqu’un a une solution, je suis preneur.

Quoiqu’il en soit du nommage des métriques, ce graphe présente l’ensemble de celles afférentes aux processus php5-fpm. Ce type de graphe est très utile pour correctement dimensionner un serveur php5-fpm.

Et un autre graphe que j’aime voir rester plat, toutes valeurs à zéro.

Représentation des queues FPM dans Grafana
Représentation des queues FPM dans Grafana

Il serait sûrement plus judicieux de faire autre chose qu’un graphe sur ce genre de valeurs censées rester à zéro. La première chose qui vient à l’esprit : Les notifications. Mais chaque chose en son temps !

À suivre…

Il nous faut encore superviser un serveur Apache2, Nginx, MySQL et bien sûr le système pour être proche d’une supervision interne complète d’un serveur web « classique ». À compléter bien sûr d’un monitoring externe comme peut en proposer Check my Website !

Olivier Jan

À propos de l’auteur

| Cofondateur de Check my Website.

Check My Website a arrêté son activité en 2017, n'hésitez pas à vous tourner vers Dareboost.