Le WordPress d'aujourd'hui, décodé pour les développeurs

Hébergement & serveurs

Too many open files : l’erreur ulimit qui plante un serveur sous charge

En pleine affluence, un site cesse de répondre sans message clair côté PHP. La cause se cache dans une limite système héritée d'une installation par défaut.

Par WordPress Développement • 23 septembre 2023 • 4 min de lecture • Aucun commentaire
Too many open files : l'erreur ulimit qui plante un serveur sous charge

Too many open files. Cette ligne apparaît dans le journal système (souvent via journalctl -u php8.1-fpm) pendant un pic de trafic, jamais avant, ce qui rend le diagnostic particulièrement trompeur : le site fonctionne parfaitement en test, et cesse de répondre uniquement sous forte affluence, sans qu’aucun message clair ne remonte dans les journaux applicatifs de WordPress lui-même.

Symptôme

Le serveur web répond de plus en plus lentement puis cesse totalement de traiter de nouvelles requêtes, alors que le CPU et la RAM restent dans des plages normales selon la supervision d’infrastructure. Les connexions à la base de données peuvent également commencer à échouer de manière intermittente, ce qui égare parfois le diagnostic vers MySQL plutôt que vers le système d’exploitation.

  • Le service PHP-FPM redémarre seul ou refuse de nouvelles connexions sous charge
  • Le message d’erreur système ne concerne aucune requête SQL spécifique
  • Le problème disparaît temporairement après un redémarrage du service, puis revient au prochain pic

Diagnostic : la limite ulimit en cause

Chaque connexion réseau ouverte, chaque fichier temporaire créé par PHP, chaque connexion à la base de données consomme un descripteur de fichier (file descriptor) au niveau du système d’exploitation. Une limite historique de 1024 descripteurs par processus, héritée de configurations Linux anciennes, suffit largement en usage normal mais sature rapidement sous forte charge, quand des centaines de requêtes simultanées ouvrent chacune plusieurs descripteurs.

ulimit -n
# 1024

Cette commande, exécutée pour l’utilisateur système sous lequel tourne PHP-FPM, révèle immédiatement la limite active. Un site à fort trafic qui gère plusieurs centaines de requêtes concurrentes dépasse cette limite bien avant de saturer le CPU ou la mémoire.

L'essentiel à retenir : La limite par défaut d'un système Linux est souvent trop basse ; Le symptôme n'apparaît que sous forte charge ; Le correctif touche systemd, pas seulement php.ini

Correctif durable

Modifier ulimit en session interactive ne survit pas à un redémarrage du service : la limite doit être fixée au niveau de systemd, qui gère désormais le cycle de vie de PHP-FPM sur la majorité des distributions récentes.

# /etc/systemd/system/php8.1-fpm.service.d/override.conf
[Service]
LimitNOFILE=65536
sudo systemctl daemon-reload
sudo systemctl restart php8.1-fpm

Il faut également vérifier que le pool PHP-FPM lui-même (fichier www.conf ou équivalent) ne définit pas une limite plus basse via la directive rlimit_files, qui prévaudrait sinon sur le réglage systemd :

; www.conf
rlimit_files = 65536

Prévention

  1. Vérifier la limite ulimit -n effective pour l’utilisateur PHP-FPM dès la mise en production d’un nouveau serveur
  2. Fixer une limite généreuse (65536 est une valeur courante) via un override systemd documenté
  3. Surveiller le nombre de descripteurs ouverts par processus via un outil de supervision, pas seulement le CPU et la RAM
  4. Tester la limite sous charge simulée avant qu’un vrai pic de trafic ne la révèle en production

Une limite système qui ne se manifeste que sous forte charge est la pire à diagnostiquer en urgence : mieux vaut la vérifier une fois pour toutes avant le premier incident que d’y penser au milieu d’un pic de trafic réel.

Le cas de MySQL, souvent oublié

MySQL et MariaDB possèdent leur propre limite de descripteurs de fichiers ouverts, réglée séparément via la directive open_files_limit dans my.cnf, et soumise elle aussi à un plafond systemd propre au service mysql ou mariadb. Corriger uniquement la limite de PHP-FPM sans vérifier celle de la base de données laisse une porte ouverte au même symptôme, simplement déplacé d’un service à l’autre.

# /etc/mysql/mariadb.conf.d/50-server.cnf
open_files_limit = 20000
# /etc/systemd/system/mariadb.service.d/override.conf
[Service]
LimitNOFILE=20000

En résumé

« Too many open files » n’est jamais un problème de requêtes SQL mal optimisées, même si le symptôme y ressemble sous charge : c’est une limite système par processus, héritée d’une configuration par défaut trop conservatrice. Le correctif se situe au niveau de systemd et du pool PHP-FPM, mais concerne également la base de données elle-même, souvent oubliée dans le même audit alors qu’elle est soumise à la même contrainte système.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi