Laravel Octane en 2026 : Swoole, RoadRunner et Optimisation des Performances
Guide complet sur Laravel Octane 2.19 : choix entre FrankenPHP, Swoole et RoadRunner, prévention des fuites mémoire, et configuration pour la production.

Laravel Octane transforme les performances des applications PHP en conservant le framework initialisé en mémoire entre les requêtes. La version 2.19 (août 2026) prend en charge trois serveurs prêts pour la production : FrankenPHP, Swoole, et RoadRunner. Chacun répond à des contraintes opérationnelles différentes, et choisir le mauvais coûte soit en performance, soit en stabilité.
FrankenPHP : configuration la plus simple, HTTP/3 natif, binaire unique. RoadRunner : binaire Go éprouvé, aucune extension PHP requise. Swoole : débit maximal avec concurrence par coroutines, nécessite la gestion d'une extension PECL.
Comment Octane Élimine le Coût d'Initialisation
PHP-FPM traditionnel crée un nouveau processus par requête. Laravel initialise son conteneur de services, charge la configuration, enregistre les providers et résout les middlewares à chaque appel HTTP. Octane inverse ce modèle : l'application démarre une seule fois par worker, puis la même instance traite des milliers de requêtes de façon séquentielle.
Le gain de performance provient de l'élimination du travail répétitif. Une application Laravel 12 typique passe entre 15 et 40ms à s'initialiser avant d'exécuter la logique métier. Avec Octane, ce coût tombe à zéro après la première requête. Les benchmarks sur du matériel identique montrent des améliorations de débit de 2x à 4x pour les endpoints API, avec un écart qui se creuse à mesure que la complexité de l'application augmente.
return [
'server' => env('OCTANE_SERVER', 'frankenphp'),
// Workers handle HTTP requests
'workers' => env('OCTANE_WORKERS', 8),
// Gracefully restart workers after N requests to prevent memory bloat
'max_requests' => env('OCTANE_MAX_REQUESTS', 500),
// Task workers for Swoole concurrent operations
'task_workers' => env('OCTANE_TASK_WORKERS', 6),
// Maximum execution time per request in seconds
'max_execution_time' => 30,
];Le paramètre max_requests agit comme une soupape de sécurité. Même du code bien écrit peut accumuler de la mémoire sur des centaines de requêtes. Fixer cette valeur à 500 force les workers à redémarrer avant que la pression mémoire ne devienne problématique.
FrankenPHP : Le Choix Par Défaut en 2026 pour les Nouveaux Projets
FrankenPHP se distribue sous forme de binaire unique construit sur Caddy et PHP. Il gère automatiquement les certificats HTTPS via Let's Encrypt, supporte HTTP/3 nativement, et ne nécessite aucune extension PHP à installer. L'installateur Laravel et les exemples de production utilisent désormais FrankenPHP par défaut.
# Install Octane with FrankenPHP
composer require laravel/octane
php artisan octane:install --server=frankenphp
# Start the server
php artisan octane:start --server=frankenphp --host=0.0.0.0 --port=8000Pour les déploiements conteneurisés, FrankenPHP fournit des images Docker officielles :
# Dockerfile
FROM dunglas/frankenphp
RUN install-php-extensions \
pcntl \
pdo_pgsql \
redis
COPY . /app
ENTRYPOINT ["php", "artisan", "octane:frankenphp"]La configuration Docker Compose pour le développement active HTTPS et HTTP/3 :
# compose.yaml
services:
frankenphp:
build:
context: .
entrypoint: php artisan octane:frankenphp --workers=1 --max-requests=1
ports:
- "443:443"
- "443:443/udp"
volumes:
- .:/appFrankenPHP gère les redémarrages de workers de manière élégante et s'intègre directement au système de middlewares de Caddy pour les scénarios de routage avancés.
RoadRunner : Stabilité Go Sans Dépendances d'Extension
RoadRunner se compile en binaire Go qui gère les processus workers PHP. Il communique avec PHP via un protocole binaire, conservant la gestion des workers et le traitement HTTP en Go tout en exécutant le code applicatif en PHP. Cette architecture offre une isolation des processus : un worker PHP qui plante n'affecte pas le parent Go ni les workers voisins.
# Install Octane with RoadRunner
composer require laravel/octane spiral/roadrunner-cli spiral/roadrunner-http
php artisan octane:install --server=roadrunner
# Download the RoadRunner binary
./vendor/bin/rr get-binary
# Start the server
php artisan octane:start --server=roadrunner --host=0.0.0.0 --port=8000La configuration RoadRunner se trouve dans .rr.yaml à la racine du projet :
# .rr.yaml
version: "3"
server:
command: "php artisan octane:start --server=roadrunner --host=0.0.0.0 --port=8000"
relay: pipes
http:
address: 0.0.0.0:8000
middleware: ["headers", "gzip"]
pool:
num_workers: 8
max_jobs: 500
supervisor:
max_worker_memory: 128Le paramètre max_worker_memory (en Mo) termine les workers qui dépassent les limites de mémoire, offrant un filet de sécurité supplémentaire au-delà de max_requests. Pour les équipes avec des pipelines CI établis et une infrastructure PHP-FPM existante, RoadRunner offre le chemin de migration le plus fluide.
Swoole : Débit Maximal avec Concurrence par Coroutines
Swoole fonctionne comme une extension PHP qui remplace le cycle de vie standard des requêtes par un runtime événementiel capable de gérer des coroutines. Elle fournit des fonctionnalités indisponibles sur les autres serveurs : exécution concurrente de tâches, ticks et intervalles, et un cache en mémoire avec un débit de 2 millions d'opérations par seconde.
# Install Swoole via PECL
pecl install swoole
# Add to php.ini
echo "extension=swoole.so" >> $(php --ini | grep "Loaded Configuration" | cut -d: -f2 | xargs)/php.ini
# Install Octane with Swoole
composer require laravel/octane
php artisan octane:install --server=swoole
# Start with task workers for concurrent operations
php artisan octane:start --server=swoole --workers=8 --task-workers=6L'exécution concurrente de tâches de Swoole gère les opérations I/O parallèles au sein d'une seule requête :
use App\Models\User;
use App\Models\Order;
use App\Models\Analytics;
use Laravel\Octane\Facades\Octane;
class DashboardController extends Controller
{
public function index()
{
// Execute three queries concurrently instead of sequentially
[$users, $orders, $analytics] = Octane::concurrently([
fn () => User::active()->count(),
fn () => Order::today()->sum('total'),
fn () => Analytics::hourly()->get(),
]);
return view('dashboard', compact('users', 'orders', 'analytics'));
}
}Sans Octane::concurrently(), ces trois requêtes s'exécutent séquentiellement : 50ms + 30ms + 40ms = 120ms au total. Avec l'exécution concurrente, le temps total égale la requête la plus lente : 50ms. Le flag --task-workers contrôle le nombre d'opérations concurrentes pouvant s'exécuter simultanément à travers tous les workers de requêtes.
Les tâches concurrentes, ticks, intervalles, cache Octane et tables Swoole nécessitent l'extension Swoole. FrankenPHP et RoadRunner ne supportent pas ces fonctionnalités. Évaluez si votre application en a besoin avant de vous engager dans la complexité opérationnelle de Swoole.
Prévention des Fuites Mémoire : Écrire du Code Sans État
La performance d'Octane vient de l'état persistant, ce qui crée le principal défi : du code qui fonctionnait parfaitement sous PHP-FPM peut fuir de la mémoire de façon catastrophique sous Octane. L'instance de l'application survit entre les requêtes, donc les propriétés statiques, les singletons et l'état global s'accumulent.
Trois patterns causent la plupart des fuites mémoire :
Tableaux statiques qui croissent sans limite :
// WRONG: Memory leak - array grows with every request
class MetricsCollector
{
public static array $data = [];
public static function record(string $metric): void
{
self::$data[] = $metric; // Never cleared between requests
}
}
// CORRECT: Use request-scoped storage or external systems
class MetricsCollector
{
public function record(string $metric): void
{
Redis::lpush('metrics', $metric); // External storage
}
}Singletons contenant des données spécifiques à la requête :
// WRONG: First request's user leaks into subsequent requests
$this->app->singleton(UserContext::class, function ($app) {
return new UserContext($app['request']->user());
});
// CORRECT: Use closures for deferred resolution
$this->app->singleton(UserContext::class, function ($app) {
return new UserContext(fn () => $app['request']->user());
});Injection du conteneur et de la requête dans les constructeurs :
// WRONG: Captures stale container/request
class PaymentService
{
public function __construct(
private Application $app,
private Request $request
) {}
}
// CORRECT: Inject via method parameters or use helpers
class PaymentService
{
public function processPayment(Request $request): void
{
$user = $request->user();
$config = config('services.stripe.key'); // Global helper, always fresh
}
}Les helpers globaux app(), request(), et config() retournent toujours les valeurs courantes. Les utiliser au lieu de l'injection par constructeur évite la plupart des fuites liées aux singletons.
Patterns de Déploiement en Production
Les serveurs Octane nécessitent une supervision des processus pour redémarrer en cas de crash. Supervisor gère cela de manière fiable :
; /etc/supervisor/conf.d/octane.conf
[program:octane]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/app/artisan octane:start --server=frankenphp --host=127.0.0.1 --port=8000
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/app/storage/logs/octane.log
stopwaitsecs=3600Pour les déploiements, les workers Octane doivent se recharger pour prendre en compte le nouveau code. La commande octane:reload gère cela avec élégance, attendant que les requêtes en cours se terminent avant de recycler les workers :
# In deployment script (after git pull, composer install, etc.)
php artisan octane:reloadNginx se place devant Octane pour servir les assets statiques et terminer SSL :
# /etc/nginx/sites-available/app.conf
upstream octane {
server 127.0.0.1:8000;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name example.com;
root /var/www/app/public;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
try_files $uri $uri/ @octane;
}
location @octane {
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
proxy_pass http://octane;
}
}La directive keepalive maintient des connexions persistantes entre Nginx et Octane, réduisant le coût des handshakes TCP pour les requêtes proxifiées.
Prêt à réussir tes entretiens Laravel ?
Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.
Arbre de Décision pour le Choix du Serveur
Choisir entre FrankenPHP, RoadRunner et Swoole dépend des contraintes opérationnelles et des exigences de l'application :
| Exigence | Serveur Recommandé |
|---|---|
| Configuration la plus simple, déploiement conteneurisé | FrankenPHP |
| Support HTTP/3 natif | FrankenPHP |
| Pas de dépendances d'extension PHP | FrankenPHP ou RoadRunner |
| Isolation maximale des processus | RoadRunner |
| Infrastructure PHP-FPM établie | RoadRunner |
| I/O concurrent au sein des requêtes | Swoole |
| Cache en mémoire (2M ops/sec) | Swoole |
| Ticks, intervalles, tâches de fond | Swoole |
| Tables Swoole pour état partagé | Swoole |
Pour les équipes démarrant de nouveaux projets en 2026, FrankenPHP offre le meilleur équilibre entre simplicité et capacité. La migration d'applications existantes fonctionne mieux avec RoadRunner grâce à son isolation des processus et son modèle de déploiement familier. Swoole convient aux APIs à haut débit qui bénéficient de la concurrence par coroutines et nécessitent des fonctionnalités spécifiques à Swoole.
Questions d'Entretien sur Laravel Octane
Les entretiens techniques couvrent de plus en plus Octane à mesure que les applications Laravel à fort trafic l'adoptent. Questions courantes et ce que recherchent les recruteurs :
"Comment Octane atteint-il ses gains de performance ?"
La réponse attendue : Octane démarre Laravel une fois par worker et réutilise cette instance entre les requêtes, éliminant le coût d'initialisation de 15-40ms à chaque requête. Les candidats doivent mentionner que les méthodes register et boot des service providers s'exécutent une fois par worker, pas par requête.
"Qu'est-ce qui cause les fuites mémoire dans les applications Octane ?"
Les bonnes réponses identifient trois sources : les tableaux statiques qui accumulent des données, les singletons capturant l'état spécifique à la requête, et l'injection par constructeur du conteneur ou des objets de requête. Les candidats doivent expliquer que la correction implique d'utiliser des closures pour la résolution différée ou de passer les données via les paramètres de méthode.
"Quand choisiriez-vous Swoole plutôt que RoadRunner ?"
Les avantages de Swoole sont la concurrence par coroutines via Octane::concurrently(), le cache Octane haute vitesse, et des fonctionnalités comme les ticks et intervalles. Le compromis est la complexité opérationnelle : Swoole nécessite la gestion d'une extension PECL, tandis que RoadRunner se distribue comme un binaire Go. Pour les applications CRUD sans besoins d'I/O concurrent, RoadRunner est plus simple à opérer. Pour plus de préparation aux entretiens Laravel, voir Questions d'Entretien Développeur PHP Laravel 2026.
"Comment gérez-vous les déploiements avec Octane ?"
La séquence de déploiement : arrêter d'accepter de nouvelles connexions, attendre que les requêtes en cours se terminent, recharger les workers avec le nouveau code. La commande php artisan octane:reload gère cela. Les candidats doivent mentionner Supervisor ou systemd pour la supervision des processus et Nginx ou Caddy comme reverse proxy.
Monitoring et Profilage des Applications Octane
Le monitoring de la mémoire devient critique sous Octane. Les workers persistent, donc la croissance mémoire indique des fuites plutôt qu'une surcharge normale de requête. Laravel Pulse et Telescope fonctionnent tous deux avec Octane et fournissent un profilage au niveau de la requête.
use Laravel\Octane\Events\RequestReceived;
use Laravel\Octane\Events\RequestTerminated;
public function boot(): void
{
Event::listen(RequestReceived::class, function ($event) {
$event->sandbox->instance('request.memory.start', memory_get_usage());
});
Event::listen(RequestTerminated::class, function ($event) {
$start = $event->sandbox->make('request.memory.start');
$delta = memory_get_usage() - $start;
if ($delta > 1024 * 1024) { // More than 1MB growth
Log::warning('High memory delta', [
'path' => $event->request->path(),
'delta_mb' => round($delta / 1024 / 1024, 2),
]);
}
});
}Cet écouteur d'événement log les requêtes qui augmentent la mémoire de plus de 1Mo, aidant à identifier les endpoints qui nécessitent une optimisation. Pour le monitoring en production, des outils APM externes comme Datadog ou New Relic fournissent une visibilité au niveau des workers.
Intégration d'Octane avec les Queues et Horizon
Octane gère les requêtes HTTP ; Laravel Horizon gère les workers de queue. Les deux fonctionnent indépendamment et se complètent. Le traitement lourd appartient aux jobs en queue, gardant les workers Octane réactifs.
use App\Jobs\GenerateReport;
class ReportController extends Controller
{
public function generate(Request $request)
{
// Dispatch to queue instead of blocking the Octane worker
GenerateReport::dispatch($request->user(), $request->input('parameters'));
return response()->json(['status' => 'processing']);
}
}Pour des patterns connexes sur le traitement en arrière-plan, voir Laravel Queues and Jobs: Asynchronous Architecture et Laravel Middleware Deep Dive.
Ce Qu'il Faut Retenir sur Laravel Octane en 2026
- Octane 2.19 supporte trois serveurs : FrankenPHP (le plus simple), RoadRunner (le plus stable), et Swoole (le plus de fonctionnalités)
- Les gains de performance viennent de l'élimination de l'initialisation par requête ; attendez une amélioration du débit de 2x à 4x
- Les fuites mémoire surviennent parce que l'état des workers persiste ; évitez les tableaux statiques, les requêtes injectées par constructeur, et les singletons avec des données de requête
- Utilisez
--max-requests=500pour forcer le recyclage des workers avant que la pression mémoire ne s'accumule - Les fonctionnalités exclusives à Swoole incluent
Octane::concurrently(), ticks, intervalles, et le cache Octane - Déployez derrière Nginx ou Caddy avec Supervisor pour la gestion des processus
- Profilez la croissance mémoire par requête ; des deltas supérieurs à 1Mo indiquent des fuites potentielles
- Mettez le travail lourd en queue via Horizon ; gardez les workers Octane pour les réponses HTTP rapides
Passe à la pratique !
Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.
Tu saurais repérer le bug en Laravel ?
Un vrai bout de code, un bug caché, une tentative par jour. Sans compte pour essayer.

Écrit par
Anthony Fillion-MailletFondateur de SharpSkill
Développeur fullstack depuis plus de 10 ans. Il dirige SharpSkill et répond de tout ce qui y est publié.
Mis à jour le 11 septembre 2026
Tags
Partager
Articles similaires

Solutions Laravel : Patterns Avancés, Débogage et Questions d'Entretien 2026
Maîtriser les solutions Laravel avec les patterns architecturaux avancés, les techniques de débogage et les connaissances essentielles pour les entretiens. Classes de service, pattern Repository, débogage avec Telescope et questions fréquentes.

Laravel Livewire 3 en 2026 : Applications Réactives et Questions d'Entretien
Maîtrisez Laravel Livewire 3 avec ce guide complet sur les composants réactifs, l'intégration Alpine.js, la validation en temps réel et les questions d'entretien technique.

Tests Laravel avec Pest 5 en 2026 : TIA, Mocking et Questions d'Entretien
Maitrisez les bonnes pratiques de tests Laravel avec Pest 5, le Test Impact Analysis, Mockery, les fakes de facades et les tests d'architecture. Couvre les tests unitaires, tests fonctionnels, strategies de mocking et questions d'entretien courantes pour les developpeurs Laravel.