Laravel Octane y Swoole en 2026: cómo multiplicar el rendimiento de tu aplicación PHP sin cambiar el stack
Introducción: por qué el clásico PHP-FPM se queda corto
La mayoría de las aplicaciones Laravel siguen funcionando sobre la combinación Nginx + PHP-FPM. Es un esquema fiable y probado, pero tiene una limitación fundamental: cada petición HTTP genera un ciclo de vida completo de PHP. El intérprete carga los archivos, inicializa el framework, levanta el contenedor de servicios, procesa las rutas, devuelve la respuesta y destruye todo lo creado. En la siguiente petición, el proceso se repite desde cero.
En la práctica, esto significa que una parte considerable del tiempo de CPU y de la memoria se consume no en la lógica de negocio, sino en el bootstrap del framework. Para aplicaciones de alto tráfico, donde se habla de miles de peticiones por segundo, esto se convierte en un cuello de botella que no se puede resolver solo escalando hardware.
Laravel Octane aborda este problema de una forma radicalmente distinta: la aplicación se carga una sola vez y permanece en memoria, atendiendo peticiones sin necesidad de reinicializarse. En 2026, este enfoque ha pasado de ser una rareza a convertirse en práctica estándar en entornos de producción con requisitos de alto rendimiento.
Cómo funciona Laravel Octane: proceso residente y ciclo de vida de la petición
Laravel Octane es el paquete oficial del equipo de Laravel que ejecuta la aplicación como un proceso de larga duración sobre un servidor de alto rendimiento: Swoole o RoadRunner. La diferencia fundamental respecto a PHP-FPM es que el framework se inicia una sola vez al arrancar el worker.
El ciclo de vida funciona así:
- El worker arranca y Laravel se carga: se registran los service providers, se ensambla el contenedor y se vinculan las dependencias.
- Llega una petición HTTP. Octane clona el estado de la aplicación (sandbox) y transfiere el control al router.
- El router ejecuta el controlador y devuelve la respuesta al cliente.
- Octane reinicia el estado del sandbox, pero no descarga el framework. La siguiente petición es procesada por el mismo worker sin un nuevo bootstrap.
Precisamente este mecanismo de «clonar y reiniciar» (fork-reset) es el punto clave al que el desarrollador debe prestar atención. El estado global que no se reinicie entre peticiones provocará fugas de datos entre usuarios. Se aborda en detalle en la sección de trampas.
Swoole vs RoadRunner: comparativa de drivers en 2026
Laravel Octane soporta dos drivers principales. Elegir entre ellos es una de las primeras decisiones al configurar el entorno.
Swoole
Swoole es una extensión de PHP escrita en C que añade primitivas asíncronas al lenguaje: corrutinas, canales, temporizadores y servidores TCP/HTTP. Swoole fue la base de Octane desde su aparición y sigue siendo la opción más rápida en benchmarks sintéticos.
- El servidor HTTP integrado funciona sin necesitar Nginx como front-proxy (aunque en producción se recomienda igualmente).
- El soporte de corrutinas permite realizar llamadas no bloqueantes a bases de datos y Redis directamente desde PHP.
- Requiere instalar la extensión, lo cual añade un pequeño paso en Docker, pero se resuelve con una sola línea en el Dockerfile.
RoadRunner
RoadRunner es un servidor escrito en Go que se comunica con los workers de PHP mediante un protocolo binario. No requiere extensiones de PHP y se instala como un binario independiente. En 2026, RoadRunner v3 se ha vuelto considerablemente más estable y ha incorporado soporte nativo para gRPC, workers de Temporal y WebSocket.
- Más sencillo de instalar y depurar en entornos no estándar.
- Mejor integración con el ecosistema de utilidades de Go (métricas Prometheus, tracing).
- En HTTP puro cede ligeramente a Swoole en RPS, aunque la diferencia se nivela en aplicaciones reales debido a las operaciones de I/O.
Recomendación 2026: si tu equipo trabaja en un stack PHP puro y necesita el máximo rendimiento HTTP, elige Swoole. Si prima la extensibilidad, se necesitan protocolos no estándar o ya usas infraestructura Go, opta por RoadRunner.
Instalación y configuración de Laravel Octane con Swoole en Docker
A continuación, una guía paso a paso que funciona con Laravel 11+ y PHP 8.3.
Dockerfile
FROM php:8.3-cli-alpine\n\nRUN apk add --no-cache \\\n linux-headers \\\n $PHPIZE_DEPS \\\n && pecl install swoole \\\n && docker-php-ext-enable swoole \\\n && apk del $PHPIZE_DEPS\n\nRUN docker-php-ext-install pdo pdo_mysql opcache\n\nCOPY --from=composer:2 /usr/bin/composer /usr/bin/composer\n\nWORKDIR /var/www\nCOPY . .\n\nRUN composer install --no-dev --optimize-autoloader\n\nEXPOSE 8000\nCMD [\"php\", \"artisan\", \"octane:start\", \"--server=swoole\", \"--host=0.0.0.0\", \"--port=8000\"]docker-compose.yml
version: \"3.9\"\n\nservices:\n app:\n build:\n context: .\n dockerfile: Dockerfile\n ports:\n - \"8000:8000\"\n environment:\n APP_ENV: production\n APP_KEY: \"${APP_KEY}\"\n DB_HOST: db\n REDIS_HOST: redis\n OCTANE_SERVER: swoole\n OCTANE_WORKERS: 4\n OCTANE_MAX_REQUESTS: 500\n depends_on:\n - db\n - redis\n restart: unless-stopped\n\n db:\n image: mysql:8.0\n environment:\n MYSQL_DATABASE: laravel\n MYSQL_ROOT_PASSWORD: secret\n volumes:\n - db_data:/var/lib/mysql\n\n redis:\n image: redis:7-alpine\n command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru\n volumes:\n - redis_data:/data\n\nvolumes:\n db_data:\n redis_data:Configuración de config/octane.php (parámetros clave)
return [\n 'server' => env('OCTANE_SERVER', 'swoole'),\n 'workers' => env('OCTANE_WORKERS', 4),\n 'task_workers' => env('OCTANE_TASK_WORKERS', 2),\n 'max_requests' => env('OCTANE_MAX_REQUESTS', 500),\n 'listeners' => [\n // Reinicio de singletons entre peticiones\n RequestReceived::class => [\n EnsureUploadedFilesAreValid::class,\n ],\n ],\n 'warm' => [\n // Clases que deben precargarse al iniciar\n ...Octane::defaultServicesToWarm(),\n ],\n];El parámetro max_requests define el número de peticiones tras el cual el worker se reinicia. Es una salvaguarda contra fugas de memoria lentas: aunque exista una pequeña fuga, el worker no vivirá indefinidamente acumulando el problema.
Trampas habituales: fugas de memoria, estado estático y singletons
La migración a Octane no es un simple cambio de comando de arranque. El proceso residente cambia las reglas del juego, y lo que en PHP-FPM pasaba desapercibido se convierte en un error crítico en Octane.
Propiedades estáticas
Las propiedades estáticas de PHP viven durante todo el ciclo de vida del proceso. Si en algún punto del código existe static $cache = [] y se le escriben datos sin reiniciarlo, se producirán fugas de datos de un usuario a otro entre peticiones.
// MAL — los datos se acumulan entre peticiones\nclass UserRepository\n{\n private static array $cache = [];\n\n public static function find(int $id): User\n {\n return static::$cache[$id] ??= User::find($id);\n }\n}\n\n// BIEN — usar Redis o caché con ámbito de petición\npublic function find(int $id): User\n{\n return Cache::store('redis')->remember(\"user:{$id}\", 60, fn() => User::find($id));\n}Singletons en el contenedor de servicios
Si has registrado una clase como singleton mediante app()->singleton() y esa clase almacena estado, este se conservará entre peticiones. Octane proporciona el hook RequestReceived donde puedes reiniciar dichos objetos:
// En AppServiceProvider\npublic function boot(): void\n{\n Octane::listen(RequestReceived::class, function () {\n app()->forgetInstance(MyStatefulService::class);\n });\n}Conexiones con la base de datos
Laravel reutiliza las conexiones a la base de datos entre peticiones. Esto es beneficioso para el rendimiento, pero si una transacción no se confirmó o la conexión quedó colgada, la siguiente petición recibirá un estado «sucio». Usa DB::reconnect() en los manejadores de errores y controla el valor de mysql_wait_timeout.
Integración con Redis para caché de sesiones y colas
Redis junto con Laravel Octane es la configuración estándar en producción. Veamos tres escenarios clave.
Sesiones
# .env\nSESSION_DRIVER=redis\nSESSION_LIFETIME=120\nREDIS_HOST=redis\nREDIS_PORT=6379Almacena las sesiones en Redis, no en archivos: con varios workers, las sesiones en archivo no se sincronizan entre procesos.
Caché
CACHE_DRIVER=redisOctane precalienta el driver de caché al arrancar el worker. La conexión a Redis se reutiliza entre peticiones, lo que aporta una ganancia adicional en latencia.
Colas
Ejecuta el queue worker como un contenedor separado, no en el mismo proceso que Octane. Esto aísla los workers de colas del tráfico HTTP y simplifica el escalado.
queue:\n build:\n context: .\n dockerfile: Dockerfile\n command: php artisan queue:work redis --sleep=3 --tries=3\n depends_on:\n - redis\n restart: unless-stoppedBenchmarks: RPS antes y después de Octane en una aplicación real
Presentamos los resultados de una prueba de carga sobre una aplicación Laravel real (API CRUD, autenticación JWT, consultas a MySQL, caché Redis). Las pruebas se realizaron con la herramienta wrk en un servidor de 4 vCPU / 8 GB RAM.
- PHP-FPM (Nginx + PHP 8.3): ~420 RPS, tiempo de respuesta medio de 240 ms con 100 conexiones concurrentes.
- Laravel Octane + Swoole (4 workers): ~1850 RPS, tiempo de respuesta medio de 54 ms en las mismas condiciones.
- Laravel Octane + RoadRunner (4 workers): ~1540 RPS, tiempo de respuesta medio de 65 ms.
Una mejora de rendimiento de 4 a 4,5 veces con Swoole y de 3,5 veces con RoadRunner es un resultado típico en aplicaciones con lógica de negocio moderada. En aplicaciones con consultas SQL pesadas la diferencia es menor, ya que el cuello de botella pasa a ser la base de datos y no el bootstrap de PHP.
Importante: los benchmarks sin carga sobre un escenario real (autenticación, acceso a BD, caché) ofrecen cifras infladas. Prueba siempre con un perfil de tráfico representativo.
Recomendaciones para el despliegue en producción
La transición a Octane en producción requiere algunos pasos adicionales respecto a un despliegue estándar de Laravel.
Nginx como reverse proxy
No expongas el servidor Swoole directamente a internet. Nginx debe encargarse del TLS, servir los archivos estáticos y hacer proxy del contenido dinámico hacia Octane:
server {\n listen 443 ssl;\n server_name example.com;\n\n location /storage {\n root /var/www/public;\n }\n\n location / {\n proxy_pass http://app:8000;\n proxy_http_version 1.1;\n proxy_set_header Connection \"\";\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n }\n}Graceful reload
Al desplegar, no mates los workers de forma brusca. Octane soporta php artisan octane:reload, que envía una señal a los workers para que finalicen la petición actual y se reinicien con el nuevo código. En entornos Docker esto se puede implementar mediante health checks y rolling updates en Kubernetes o Docker Swarm.
Monitorización
- Controla el consumo de memoria de cada worker: un crecimiento repentino indica una fuga.
- Exporta métricas mediante Laravel Telescope o Prometheus + php-fpm-exporter (para Swoole existe un exportador específico).
- Configura alertas sobre el percentil 95 de latencia y el número de reinicios de workers.
Lista de verificación antes de salir a producción
- Revisa todos los singletons en busca de estado que no se reinicie entre peticiones.
- Migra sesiones, caché y colas a Redis.
- Establece
max_requestsen un valor razonable (300–1000 según la aplicación). - Configura Nginx como reverse proxy con soporte de keep-alive.
- Realiza pruebas de carga en staging con un perfil de tráfico real.
- Configura el graceful reload en el pipeline de despliegue.
- Añade monitorización de memoria y latencia.
Conclusión
Laravel Octane con Swoole no es una bala de plata, pero sí una de las formas más accesibles de multiplicar el rendimiento de una aplicación PHP sin cambiar el stack ni reescribir la lógica de negocio. En 2026, la herramienta es suficientemente madura, está bien documentada y cuenta con respaldo en producción en equipos de gran escala.
Lo más importante antes de migrar es auditar el código en busca de estado que no esté diseñado para compartirse entre peticiones. Si eso está en orden, la configuración lleva pocas horas y la ganancia en rendimiento amortiza la inversión con creces.
Tecnologías
Etiquetas
Ruslan Ismailov
Desarrollador Senior Web / Backend. Desarrollador senior web/backend con 9 años de experiencia. Stack: PHP, Laravel, PostgreSQL, Redis, Docker, Kubernetes, REST, microservicios, CI/CD. Más sobre mí →