Serveurs hautes performances avec Swoole
Gérez des milliers de connexions avec Swoole et ses coroutines.
Serveurs hautes performances avec Swoole est une leçon PHP Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage PHP Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours PHP Academy comprend 4 leçons au total.
Ce qu'est Swoole
Swoole (ainsi que son fork OpenSwoole) est une extension C qui transforme PHP en un environnement d'exécution hautes performances, piloté par les coroutines et les événements. Au lieu que PHP-FPM crée un processus par requête, un serveur Swoole initialise votre application une seule fois et la conserve en mémoire, en traitant les requêtes avec un pool de processus de travail persistants et des coroutines intégrées. Résultat : des gains de débit considérables et une concurrence native au sein d'une seule requête.
Le serveur HTTP persistant
L'exemple classique : un serveur HTTP complet dans un script. Il écoute, distribue chaque requête à un processus de travail et ne réinitialise jamais le cadriciel. Notez que cela nécessite ext-swoole : cela ne fonctionne pas avec le PHP CLI standard.
<?php
$server = new Swoole\Http\Server('0.0.0.0', 9501);
$server->set(['worker_num' => 4]);
$server->on('request', function ($request, $response) {
$response->header('Content-Type', 'application/json');
$response->end(json_encode(['hello' => $request->server['request_uri']]));
});
echo "listening on :9501\n";
$server->start();Des coroutines, pas des rappels
La fonctionnalité phare de Swoole est constituée par les coroutines : vous écrivez du code séquentiel de style bloquant que l'environnement d'exécution planifie de manière coopérative. Coroutine\run() ouvre un contexte de coroutine ; go() lance une nouvelle coroutine. Chaque coroutine possède sa propre pile, comme une fibre, mais Swoole les planifie automatiquement aux points d'entrée-sortie.
<?php
use Swoole\Coroutine as Co;
Co\run(function () {
go(function () { Co::sleep(1); echo "A done\n"; });
go(function () { Co::sleep(1); echo "B done\n"; });
// Both sleep concurrently -> total ~1s, not 2s
});Fonctions bloquantes interceptées
Le mécanisme qui rend les coroutines agréables à utiliser : les crochets de l'environnement d'exécution. Swoole réécrit de manière transparente les appels bloquants : PDO, Redis, curl, sleep, file_get_contents, pour en faire des versions non bloquantes compatibles avec les coroutines. Votre appel ordinaire $pdo->query() suspend la coroutine au lieu de figer le processus de travail.
<?php
use Swoole\Runtime;
use Swoole\Coroutine as Co;
Runtime::enableCoroutine(SWOOLE_HOOK_ALL); // hook PDO, curl, sleep, etc.
Co\run(function () {
go(function () { sleep(1); echo "task 1\n"; }); // sleep() is now async!
go(function () { sleep(1); echo "task 2\n"; });
}); // finishes in ~1s because sleep was hookedEntrées-sorties concurrentes avec WaitGroup
Pour répartir le travail puis attendre sa fin, Swoole propose un WaitGroup (semblable au sync.WaitGroup de Go). Lancez des coroutines, appelez add() pour chaque tâche, done() à la fin de chacune, puis wait() pour attendre leur achèvement : elles s'exécutent simultanément.
<?php
use Swoole\Coroutine as Co;
use Swoole\Coroutine\WaitGroup;
Co\run(function () {
$wg = new WaitGroup();
$results = [];
foreach (['eu', 'us', 'asia'] as $region) {
$wg->add();
go(function () use ($wg, $region, &$results) {
Co::sleep(0.5); // simulated API call
$results[$region] = "ok-$region";
$wg->done();
});
}
$wg->wait(); // all three ran in parallel (~0.5s)
var_dump($results);
});Des canaux pour communiquer
Les coroutines se coordonnent au moyen de canaux : des files d'attente typées et limitées qui suspendent le producteur lorsqu'elles sont pleines et le consommateur lorsqu'elles sont vides. Il s'agit d'une communication de type CSP, qui évite entièrement les verrous sur l'état partagé.
<?php
use Swoole\Coroutine as Co;
use Swoole\Coroutine\Channel;
Co\run(function () {
$chan = new Channel(2);
go(function () use ($chan) {
foreach (range(1, 3) as $n) $chan->push($n);
$chan->push(null); // sentinel
});
go(function () use ($chan) {
while (($v = $chan->pop()) !== null) echo "got $v\n";
});
});Regroupement des connexions
Un serveur persistant ne doit pas ouvrir une connexion à la base de données pour chaque requête. Swoole fournit des pools de connexions compatibles avec les coroutines : les processus de travail réutilisent un ensemble fixe de connexions entre des milliers de coroutines concurrentes, ce qui élimine le renouvellement incessant des connexions.
<?php
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;
use Swoole\Coroutine as Co;
Co\run(function () {
$pool = new PDOPool((new PDOConfig())
->withHost('127.0.0.1')->withDbname('app')
->withUsername('u')->withPassword('p'), 8);
go(function () use ($pool) {
$pdo = $pool->get(); // borrow
$row = $pdo->query('SELECT NOW()')->fetch();
$pool->put($pdo); // return to pool
var_dump($row);
});
});Fuites d'état : le piège de la mémoire persistante
Comme le processus reste actif d'une requête à l'autre, l'état global et statique persiste. Un cache statique qui croît sans limite, un singleton contenant des données propres à une requête ou une transaction de base de données abandonnée corrompra les requêtes suivantes et épuisera la mémoire. Règles à suivre : évitez de stocker des données propres aux requêtes dans des éléments statiques ou des singletons, réinitialisez le contexte pour chaque requête et définissez max_request afin que les processus de travail soient renouvelés périodiquement.
<?php
$server = new Swoole\Http\Server('0.0.0.0', 9501);
$server->set([
'worker_num' => 8,
'max_request' => 10000, // recycle a worker after N requests to bound leaks
]);
// Never store $request data in a static property between requests!Contexte propre à chaque coroutine
Comme un même processus de travail entrelace de nombreuses coroutines, vous ne pouvez pas utiliser de simples éléments statiques pour les données propres à chaque requête. Swoole attribue à chaque coroutine un contexte (Coroutine::getContext()) : un objet dont la durée de vie est celle de la coroutine, idéal pour l'utilisateur courant, l'identifiant de requête ou le gestionnaire de transaction.
<?php
use Swoole\Coroutine as Co;
Co\run(function () {
go(function () {
$ctx = Co::getContext();
$ctx['request_id'] = 'req-123';
// ... deep call chain can read Co::getContext()['request_id']
echo Co::getContext()['request_id'], PHP_EOL;
});
});Modèle de processus et processus de tâches
Swoole exécute un processus maître (qui gère les threads de la boucle d'événements), un gestionnaire (qui crée et surveille les processus de travail), des processus de travail (qui exécutent vos gestionnaires de requêtes et vos coroutines) et, facultativement, des processus de tâches pour les travaux lourds, bloquants ou limités par le processeur, déportés via $server->task(). Utilisez les processus de tâches pour le traitement d'images ou les longs calculs afin qu'ils ne ralentissent pas les coroutines de requêtes : vous bénéficiez ainsi à la fois de la concurrence et du parallélisme.
Différer et utiliser des minuteurs
Swoole vous permet de planifier du travail après la fin de la coroutine courante avec Coroutine::defer(), ce qui est idéal pour libérer de manière fiable les ressources regroupées, même si une exception est levée. Les minuteurs à l'échelle du serveur (Timer::tick) exécutent des tâches périodiques, comme l'actualisation du cache, dans un processus de travail sans planificateur externe.
<?php
use Swoole\Coroutine as Co;
Co\run(function () {
go(function () {
$conn = 'borrowed-connection';
Co::defer(function () use ($conn) {
echo "released $conn\n"; // runs when coroutine exits, even on error
});
echo "using $conn\n";
});
});Vérification rapide
Pourquoi devez-vous éviter de stocker les données d'une requête dans des propriétés statiques dans un serveur Swoole ?
Récapitulatif
Swoole transforme PHP en un serveur résident piloté par les coroutines :
- L'application est initialisée une seule fois ; un pool de processus de travail traite les requêtes avec des coroutines intégrées (
Co\run/go()). - Les crochets de l'environnement d'exécution rendent les opérations ordinaires de PDO, de transfert et de temporisation non bloquantes ; WaitGroup et les canaux coordonnent le travail concurrent.
- Les pools de connexions réutilisent les connexions à la base de données entre les coroutines.
- La mémoire persistante implique d'éviter les fuites d'état : utilisez
Coroutine::getContext()pour les données propres à chaque requête, définissezmax_requestet déportez le travail lourd vers des processus de tâches.
Questions Fréquemment Posées
La leçon « Serveurs hautes performances avec Swoole » est-elle gratuite ?
Oui — le texte complet de « Serveurs hautes performances avec Swoole » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours PHP Academy, passe à CoddyKit PRO. Le cours PHP Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Serveurs hautes performances avec Swoole » ?
Gérez des milliers de connexions avec Swoole et ses coroutines. Tu pratiques PHP Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer PHP Academy ?
Aucune expérience préalable n'est requise. PHP Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Serveurs hautes performances avec Swoole » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon PHP Academy ?
Oui. Chaque leçon PHP Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Modèle de concurrence de PHP
- Fibers de PHP 8.1
- Boucles d’événements avec ReactPHP
- Serveurs hautes performances avec Swoole