Swoole ou PHP-FPM: le pari risqué de l’asynchrone
Ma réponse ne vise pas à le piéger: « Très bien. Quel problème précis avez-vous mesuré avec PHP-FPM? » Là, la conversation devient beaucoup plus intéressante.
Parce que choisir entre Swoole ou PHP-FPM pour une architecture haute performance ne consiste pas à opposer l’ancien monde au nouveau. PHP-FPM n’est pas une relique embarrassante dont il faudrait s’excuser; Swoole n’est pas un bouton magique qui transforme une application lente en fusée. Ce sont deux modèles d’exécution qui ne demandent ni les mêmes compétences, ni la même discipline, ni la même maturité d’équipe.
Le marché valorise les développeurs capables de parler de performance PHP asynchrone. Mais il valorise encore davantage ceux qui savent dire: « Nous n’avons pas besoin de migrer tant que nous n’avons pas identifié le goulot d’étranglement. » Cette posture, moins spectaculaire qu’une refonte de serveur d’application PHP, est souvent celle qui protège le mieux un produit, une équipe et un budget.
PHP-FPM: un plafond visible, donc administrable
Le fonctionnement de PHP-FPM est simple à expliquer, et c’est loin d’être un défaut. Nginx reçoit la requête HTTP puis la transmet à PHP-FPM via FastCGI. PHP-FPM l’affecte à l’un de ses processus enfants disponibles. Une fois la réponse produite, le processus se libère et peut traiter une autre requête.
Le point de tension porte essentiellement sur pm.max_children. Cette directive fixe le nombre maximal de processus enfants dans un pool — autrement dit, le plafond des requêtes simultanées que ce pool peut servir. Si vingt requêtes arrivent alors que les vingt processus disponibles travaillent déjà, les suivantes attendent.
Ce n’est pas très glamour, mais c’est lisible. Et dans une architecture de production, la lisibilité a une valeur énorme.
PHP-FPM propose trois modes de gestion des processus:
| Mode | Comportement | Ce qu’il implique sur le terrain |
|---|---|---|
static | Un nombre fixe de processus est lancé | Prévisible, mais peut réserver inutilement de la mémoire en période creuse |
dynamic | Le nombre de processus varie entre un minimum et un maximum | Souple pour une charge fluctuante, à condition de suivre les montées en charge |
ondemand | Les processus sont créés à la demande puis arrêtés après une période d’inactivité | Intéressant lorsque l’activité est irrégulière, avec une attention à porter au démarrage des processus |
En modes dynamic et ondemand, pm.max_children reste le garde-fou principal. Le mode dynamic dispose aussi d’un rythme maximal de création de processus, pm.max_spawn_rate, fixé à 32 par défaut. En mode ondemand, pm.process_idle_timeout vaut 10 secondes par défaut. Ce sont des paramètres modestes en apparence, mais ils racontent beaucoup de votre rapport au trafic: anticipez-vous les pointes ou subissez-vous chaque réveil de l’application?
Lorsqu’une équipe me dit: « PHP-FPM ne tient plus », je cherche d’abord des éléments concrets dans la page d’état. Elle expose notamment la file d’attente d’écoute, son maximum atteint, les processus actifs, le signal max children reached, les requêtes lentes, le pic mémoire et la mémoire utilisée par la dernière requête.
Ces données permettent de distinguer des problèmes qui, vus de loin, se ressemblent tous:
- une file d’attente qui augmente parce que le pool est saturé;
- des processus disponibles, mais ralentis par MySQL, Redis ou un service tiers;
- une mémoire par requête qui rend impossible l’augmentation du nombre de processus;
- des requêtes lentes qui immobilisent les processus bien plus longtemps que prévu;
- une réponse Nginx mal tamponnée, qui crée une pression inutile sur la chaîne de réponse.
Nginx active d’ailleurs le tamponnage FastCGI par défaut. Ses fastcgi_buffers sont configurés par défaut à huit tampons de 4 ou 8 Kio selon la plateforme. Une réponse qui dépasse cette mémoire peut être écrite partiellement dans un fichier temporaire. Ce n’est pas une accusation contre Nginx: c’est un rappel utile. Avant de conclure que PHP est le coupable, regardez toute la chaîne.
Un pool PHP-FPM saturé n’est pas une preuve qu’il faut Swoole. C’est une question à laquelle votre supervision doit d’abord répondre.
Le vrai avantage de PHP-FPM, dans beaucoup d’équipes, tient aussi à son isolation naturelle. Une requête se termine; le processus continue, certes, mais l’exécution applicative reprend dans un cadre beaucoup plus familier à l’écosystème PHP traditionnel. Et si une bibliothèque laisse dériver la mémoire, pm.max_requests permet de recycler un processus après un nombre déterminé de requêtes. Sa valeur par défaut est 0, c’est-à-dire qu’aucun redémarrage n’est imposé. Mais ce mécanisme existe précisément pour éviter qu’une fuite mémoire connue ne devienne une dette silencieuse.
Swoole: le gain potentiel vient d’un autre contrat
Swoole propose une logique différente: concurrence pilotée par événements, opérations asynchrones et coroutines, dans des processus persistants. L’application n’est plus reconstruite à chaque cycle de traitement de la même manière; elle peut rester en mémoire et traiter plusieurs requêtes au cours de sa vie.
C’est ce modèle qui rend Swoole séduisant pour des applications où l’on attend beaucoup: appels réseau, accès à des services externes, échanges avec des files de messages, opérations d’entrées-sorties qui occupent du temps sans consommer tout le processeur. Pendant qu’une coroutine attend une réponse, une autre peut continuer son travail.
Mais attention au raccourci: concurrence ne signifie pas parallélisme CPU illimité.
Si votre opération critique est un calcul lourd, un traitement d’image ou une tâche qui monopolise le processeur, passer à Swoole ne fait pas apparaître de cœurs supplémentaires par enchantement. De même, si vos pages sont déjà majoritairement servies depuis un cache efficace, ou si votre base MySQL est le facteur limitant, la migration vers Swoole peut déplacer le problème plutôt que le résoudre.
Swoole requiert PHP 8.1 ou une version ultérieure, ainsi que l’activation de l’extension correspondante dans php.ini. Ce prérequis technique est la partie facile. La partie difficile est organisationnelle: votre équipe sait-elle maintenir une application qui vit longtemps?
Avec Laravel Octane et Swoole, par exemple, l’application est amorcée une fois puis conservée en mémoire pour servir plusieurs requêtes. La documentation de Laravel indique qu’un processus de requêtes par cœur de processeur est lancé par défaut, avec possibilité de réglage. Là encore, n’en faites pas une formule universelle. Le bon nombre de processus dépend de la mémoire réellement consommée, du processeur, des entrées-sorties, de la base de données et du profil de charge de votre application.
Dans un entretien, un responsable technique me résumait son expérience ainsi:
— « Nous avons divisé certains temps d’attente, donc la migration était une réussite. »
— « Et vos incidents après déploiement? »
— « Plus subtils. Des comportements impossibles à reproduire au premier regard. »
C’est exactement le sujet. Swoole peut améliorer une situation donnée. Il augmente aussi l’exigence de diagnostic. Une équipe qui maîtrise les métriques, les tests de charge et la gestion du cycle de vie peut en tirer un avantage réel. Une équipe qui migre parce qu’elle a vu un benchmark isolé risque, elle, d’acheter de la complexité à crédit.
L’état persistant: le détail qui devient un incident
Le cœur du comparatif PHP-FPM Swoole ne se joue pas dans une promesse de débit. Il se joue dans la durée de vie de l’état applicatif.
Avec un processus persistant, tout ce qui est placé en mémoire doit être considéré avec suspicion constructive. Un singleton qui garde une référence vers une requête, un objet de contexte mal réinitialisé, une variable globale qui conserve une donnée utilisateur, un service qui accumule des éléments au fil des appels: chacun de ces choix peut contaminer la requête suivante.
Laravel est très clair sur ce point avec Octane: injecter le conteneur ou l’objet de requête dans le constructeur d’un singleton peut conduire à manipuler une version devenue obsolète lors des requêtes suivantes. L’état global de l’application n’est pas automatiquement réinitialisé dans tous les cas.
Ce n’est pas un défaut propre à Laravel. Symfony documente le même type de risque dans son mode de travail persistant: un noyau réutilisé peut laisser fuiter l’état capturé par lui-même ou par ses services si ceux-ci ne savent pas se réinitialiser. La technologie change, le risque reste le même.
Voici les zones que je demanderais à une équipe d’auditer avant toute bascule:
1. Les services à durée de vie longue. Un singleton doit-il vraiment mémoriser une information, ou peut-il reconstruire son contexte à chaque requête? La question paraît triviale; elle ne l’est pas lorsque le projet a plusieurs années et une couche de services dense.
2. Les données liées à l’utilisateur. Langue, tenant, droits, identifiant de session, panier, traçage, en-têtes HTTP: aucune de ces données ne doit survivre par accident dans un objet partagé.
3. Les variables globales et caches internes. Un cache applicatif peut être utile, mais il faut connaître sa clé, son invalidation et son périmètre. « Cela semble fonctionner » n’est pas une stratégie de cohérence.
4. Les connexions et clients externes. Les clients MySQL, Redis, HTTP ou de messagerie doivent être évalués dans le contexte des coroutines réellement utilisées. La compatibilité ne se présume pas à partir du seul nom d’un paquet Composer.
5. Les tests qui simulent plusieurs requêtes successives dans un même processus. Un test isolé qui recrée tout l’environnement ne détectera pas nécessairement les fuites d’état que produira un processus persistant.
Avec Swoole, la question n’est pas seulement « que fait cette requête? », mais « qu’a laissé la précédente derrière elle? »
C’est là que la compétence prend une dimension très concrète sur le marché de l’emploi. Un développeur qui sait configurer une extension est utile. Celui qui sait expliquer les effets d’un état persistant sur la sécurité, l’observabilité et la maintenance apporte une valeur bien plus rare.
La mémoire: ni panique, ni déni
Les discussions sur Swoole tournent rapidement autour des fuites mémoire, parfois avec un ton catastrophiste. Restons précis: un processus PHP-FPM peut aussi avoir besoin d’être recyclé. La présence de pm.max_requests dans PHP-FPM le rappelle très explicitement. Il ne s’agit donc pas d’opposer un modèle propre à un modèle dangereux.
La différence est plutôt celle-ci: dans une application persistante, la mémoire est un sujet continu. Elle doit être observée comme un indicateur de santé, pas comme une alerte que l’on découvre après une indisponibilité.
Laravel Octane documente un redémarrage gracieux des processus après 500 requêtes par défaut, avec une option --max-requests pour modifier ce seuil. Ce chiffre mérite d’être compris, pas copié mécaniquement. Il s’agit du comportement documenté dans Laravel 10 pour Octane, pas d’une norme générale applicable à tous les usages de Swoole.
Un seuil de recyclage n’est pas un pansement honteux. C’est un garde-fou opérationnel, à condition de savoir ce qu’il protège. Si la mémoire monte doucement et sans redescendre, le recyclage peut éviter l’incident. Mais il ne dispense pas d’enquêter sur la référence conservée, le tableau qui grossit, le client qui ne libère rien ou le cache qui n’a aucune politique d’expiration.
Pour décider avec lucidité, observez au minimum:
- l’évolution de la mémoire d’un processus sur une longue séquence de requêtes représentatives;
- les redémarrages et leur effet réel sur la latence;
- le comportement sous charge simultanée, pas seulement sur une requête de démonstration;
- les erreurs intermittentes qui pourraient révéler un état partagé;
- la pression exercée sur MySQL et les autres dépendances lorsque davantage d’opérations coexistent.
Une migration réussie ne se reconnaît pas au jour où elle passe en production. Elle se reconnaît à la capacité de l’équipe à expliquer les courbes une semaine plus tard.
Le coût humain d’une migration vers Swoole
C’est le point que les comparatifs oublient souvent, alors qu’il pèse directement dans les recrutements: qui va porter le modèle après la migration?
Dans une petite équipe, l’architecte qui a introduit Swoole peut parfaitement comprendre les coroutines, les processus persistants et les subtilités de l’état mémoire. Mais si cette personne part, que reste-t-il? Une documentation de trois pages? Quelques commandes de déploiement? Une équipe qui sait redémarrer le service sans savoir diagnostiquer une fuite?
Je ne dis pas qu’il faut renoncer par prudence. Je dis qu’il faut négocier le bon périmètre de risque.
La décision devient solide lorsque vous pouvez répondre franchement à ces questions:
| Question | Réponse qui doit vous rassurer | Signal d’alerte |
|---|---|---|
| Quel problème résout-on? | Une saturation, une attente d’entrée-sortie ou une latence est mesurée et attribuée | « On nous a dit que c’était plus rapide » |
| Que conservera-t-on en mémoire? | Les services persistants et leur réinitialisation sont identifiés | Personne ne sait quels objets vivent entre deux requêtes |
| Comment valider le gain? | Un protocole de charge compare la même application et les mêmes scénarios | Un benchmark récupéré ailleurs sert de justification |
| Qui exploitera la solution? | Plusieurs personnes savent lire les métriques et intervenir | Une seule personne détient la connaissance |
| Peut-on revenir en arrière? | Le déploiement prévoit une bascule réversible vers PHP-FPM | La migration est intégrée à trop de changements simultanés |
Ce tableau n’est pas une formalité de gouvernance. C’est une grille de maturité. Dans le recrutement tech, les entreprises les plus saines ne recherchent pas des profils qui collectionnent les mots-clés. Elles recherchent des personnes capables d’assumer la conséquence d’une décision d’architecture.
Dire « je choisirais PHP-FPM, parce que le goulot est MySQL et que notre équipe a besoin d’abord d’optimiser les requêtes » peut être une réponse plus senior que « je passerais tout en asynchrone ». À l’inverse, défendre Swoole avec un périmètre testé, des dépendances auditées et un plan de repli est une vraie démonstration de maîtrise.
Ne choisissez pas une étiquette, choisissez votre problème
PHP-FPM reste un excellent choix lorsque votre application est bien observée, que son trafic est maîtrisable par dimensionnement, que vos requêtes sont correctement optimisées et que vous privilégiez une exploitation simple. Son plafond de concurrence est explicite; ses processus peuvent être recyclés; son comportement s’intègre naturellement dans une chaîne Nginx connue de nombreuses équipes.
Swoole devient pertinent lorsqu’une application souffre réellement d’attentes concurrentes, que l’architecture peut bénéficier de processus persistants et que l’équipe est prête à prendre en charge ce nouveau contrat: état réinitialisé, dépendances vérifiées, mémoire surveillée, procédures de redémarrage et tests adaptés.
La bonne question n’est donc pas: « Quel choix fera le plus moderne? » Elle est: « Quel choix crée le plus de valeur sans fragiliser notre capacité à livrer et à maintenir? »
Si vous devez défendre cette décision demain devant votre équipe ou en entretien, avancez dans cet ordre: mesurez la saturation de PHP-FPM, qualifiez la nature des attentes, auditez l’état applicatif et les dépendances, faites un essai sur un périmètre réversible, puis comparez les résultats. Pas les promesses. Les résultats.
C’est moins spectaculaire qu’un grand basculement vers l’asynchrone. C’est aussi, très souvent, la différence entre une architecture ambitieuse et une architecture réellement tenue.




