Este artículo es una traducción literal del artículo Laravel Octane Introduction del blog de Marcel Pociot. Si queres ver el artículo original, te dejo su link: https://beyondco.de/blog/laravel-octane-introduction
Decidí publicar la traducción del artículo directamente porque es tan completo y fantástico que cualquier cosa que podría decir yo, estaría de más.
PERO este viernes 9 de Abril a las 19:00 (hora Argentina) estaremos en mi canal de Twitch probando a fondo todo lo que se menciona en este artículo sobre Laravel Octane. Suscribite para enterarte cuando estemos en vivo 👉 https://www.twitch.tv/laraveltip
Laravel Octane: qué, cómo y por qué
Taylor Otwell ya mostró un vistazo del último paquete de código abierto de Laravel, Octane, durante su charla Laracon Online, pero hoy, el nuevo paquete está disponible en GitHub para que todos lo prueben beta.
En esta publicación de blog, exploraré Laravel Octane y le diré qué es, cómo puede instalarlo y usarlo, y por qué podría necesitarlo.
⚠️ Warning: Laravel Octane todavía es un software beta y aún no debe usarse en producción.
¿Qué es Laravel Octane?
Laravel Octane es un paquete de código abierto que aumentará el rendimiento de su aplicación Laravel. Laravel Octane requiere PHP 8, por lo que si todavía está en 7.x, debe actualizar su versión de PHP. Por debajo, Octane hace uso de Swoole y RoadRunner, dos servidores de aplicaciones que se encargan de servir y arrancar su aplicación Laravel. ¿Por qué es más rápido ? bueno, dejame explicarte.
Con una aplicación PHP tradicional que se sirve a través de un servidor web como nginx, cada solicitud entrante generará un worker PHP-FPM. Esto significa que cada solicitud inicia un proceso PHP individual, que ejecutará todas las tareas necesarias para atender esa solicitud.
En el caso de Laravel, esto significa que el Framework debe iniciarse, todos los proveedores de servicios registran sus servicios dentro del contenedor, todos los proveedores se inician ellos mismos, la solicitud pasa por una lista de clases de middleware, llega a su controlador, se renderiza una vista , etc. hasta que finalmente obtengamos una respuesta de nuestro servidor.
Con Swoole o RoadRunner en su lugar, todavía tenemos un worker para cada solicitud HTTP entrante, pero todos comparten el mismo framework de arranque. Esto significa que solo la primera solicitud entrante va a iniciar el framework (incluidos todos los proveedores de servicios, etc.) mientras que todas las demás solicitudes pueden hacer uso de un Framework listo para usar. Y esto es lo que hace que Octane sea tan increíblemente rápido.
Empezando con Laravel Octane
Como Laravel Octane es un paquete, debe instalarlo como una dependencia de su aplicación específica. Puede hacer esto a través del compositor:
composer require laravel/octane
Después de instalar Octane en su aplicación, asegúrese de ejecutar php artisan octane:install
. Esto publicará el archivo de configuración de Octane, además de agregar el binario rr
que genera RoadRunner al archivo .gitignore
.
Como dije, Octane va a publicar su archivo de configuración, que se ve así:
return [
/*
|--------------------------------------------------------------------------
| Octane Server
|--------------------------------------------------------------------------
|
| This value determines the default "server" that will be used by Octane
| when starting, restarting, or stopping your server via the CLI. You
| are free to change this to the supported server of your choosing.
|
*/
'server' => env('OCTANE_SERVER', 'roadrunner'),
/*
|--------------------------------------------------------------------------
| Force HTTPS
|--------------------------------------------------------------------------
|
| When this configuration value is set to "true", Octane will inform the
| framework that all absolute links must be generated using the HTTPS
| protocol. Otherwise your links may be generated using plain HTTP.
|
*/
'https' => env('OCTANE_HTTPS', false),
/*
|--------------------------------------------------------------------------
| Octane Listeners
|--------------------------------------------------------------------------
|
| All of the event listeners for Octane's events are defined below. These
| listeners are responsible for resetting your application's state for
| the next request. You may even add your own listeners to the list.
|
*/
'listeners' => [
WorkerStarting::class => [
EnsureUploadedFilesAreValid::class,
],
RequestReceived::class => [
...Octane::prepareApplicationForNextOperation(),
...Octane::prepareApplicationForNextRequest(),
//
],
RequestHandled::class => [
//
],
RequestTerminated::class => [
//
],
TaskReceived::class => [
...Octane::prepareApplicationForNextOperation(),
//
],
TickReceived::class => [
...Octane::prepareApplicationForNextOperation(),
//
],
OperationTerminated::class => [
FlushTemporaryContainerInstances::class,
// DisconnectFromDatabases::class,
// CollectGarbage::class,
],
WorkerErrorOccurred::class => [
ReportException::class,
StopWorkerIfNecessary::class,
],
WorkerStopping::class => [
//
],
],
/*
|--------------------------------------------------------------------------
| Warm / Flush Bindings
|--------------------------------------------------------------------------
|
| The bindings listed below will either be pre-warmed when a worker boots
| or they will be flushed before every new request. Flushing a binding
| will force the container to resolve that binding again when asked.
|
*/
'warm' => [
...Octane::defaultServicesToWarm(),
],
'flush' => [
//
],
/*
|--------------------------------------------------------------------------
| Garbage Collection Threshold
|--------------------------------------------------------------------------
|
| When executing long-lived PHP scripts such as Octane, memory can build
| up before being cleared by PHP. You can force Octane to run garbage
| collection if your application consumes this amount of megabytes.
|
*/
'garbage' => 50,
/*
|--------------------------------------------------------------------------
| Maximum Execution Time
|--------------------------------------------------------------------------
|
| (info) 0 means no maximum limit
|
*/
'max_execution_time' => 30,
/*
|--------------------------------------------------------------------------
| Octane Cache Table
|--------------------------------------------------------------------------
|
| While using Swoole, you may leverage the Octane cache, which is powered
| by a Swoole table. You may set the maximum number of rows as well as
| the number of bytes per row using the configuration options below.
|
*/
'cache' => [
'rows' => 1000,
'bytes' => 10000,
],
/*
|--------------------------------------------------------------------------
| Octane Swoole Tables
|--------------------------------------------------------------------------
|
| While using Swoole, you may define additional tables as required by the
| application. These tables can be used to store data that needs to be
| quickly accessed by other workers on the particular Swoole server.
|
*/
'tables' => [
'example:1000' => [
'name' => 'string:1000',
'votes' => 'int',
],
],
];
La primer clave server
es la que me permite elegir si mi aplicación utilizará swoole
o roadrunner
.
RoadRunner
RoadRunner es un servidor de aplicaciones que está escrito en Go, que no tiene dependencias de PHP. Podes elegir RoadRunner, si no deseas instalar extensiones PHP adicionales. Podes instalar RoadRunner en tu proyecto de la siguiente forma:
composer require spiral/roadrunner
Swoole
Swoole viene con un par de bonitos beneficios que RoadRunner no puede proporcionar. Como Swoole es una extensión de PHP, PHP en sí mismo obtiene algunas características nuevas interesantes, como «ticks» y «corrutinas», que voy a cubrir en un momento. Estas funciones no están disponibles con RoadRunner, por lo que si desea hacer uso de ellas, debe optar por Swoole.
Puede instalar la extensión Swoole usando:
pecl install swoole
Durante la instalación, se te preguntará si deseas tener soporte para HTTP2, curl, JSON y open_ssl dentro de Swoole. Puedes elegir con seguridad los valores predeterminados (que son off
) ya que esas configuraciones solo afectan cosas como las corrutinas. Aún podrás usar curl, JSON y todo lo demás de todas formas.
Arrancando Octane
Una vez que haya instalado RoadRunner o Swoole, y lo haya definido en tu archivo de configuración octane.php
, puedes iniciar Octane y dejar que sirva a tu aplicación Laravel de la siguiente forma:
php artisan octane:start
De forma predeterminada, Octane iniciará el servidor en el puerto 8000, por lo que puede acceder a su aplicación en un navegador a través de http://localhost:8000
.
¡Así que adelante, visite esa ruta y observe cómo vuela su aplicación Laravel! Si realiza varias solicitudes a la aplicación, puede ver que la primera es un poco más lenta; ahí es donde se inicia el Framework, mientras que las otras son notablemente más rápidas, ya que el Framework ya estará iniciado en la memoria.
200 GET / .............. 14.23 ms
200 GET / .............. 1.93 ms
200 GET / .............. 2.06 ms
Haciendo cambios en el código
Si ahora realiza un cambio de código, por ejemplo, agrega una nueva ruta /test
, e intentas ingresar a esa URL, ¡recibirá un 404! Y eso se debe a que la solicitud todavía usa el Framework (y todas las rutas) que se inició una vez que se inició el servidor Octane. Entonces, para ver ese cambio de código, debes reiniciar tu servidor Octane. Debido a que esto es muy engorroso de hacer durante el desarrollo, Octane viene con una buena manera de observar automáticamente los cambios en su base de código y reiniciar el servidor de Octane automáticamente.
Para que esto funcione, asegúrese de instalar Chokidar, una package de observación de archivos basada en NodeJS:
npm install --save-dev chokidar
A continuación, puede iniciar el servidor Octane en modo «watch»:
php artisan octane:start --watch
Ahora, la próxima vez que realice un cambio en tu código, esto se detectará y Octane reiniciará los workers y podrás ver tus cambios de inmediato.
Personalización de workers
Hablando de workers, de forma predeterminada Octane iniciará un worker por cada núcleo de CPU que tenga. Pero también puede cambiar esto, pasando una opción --workers
al comando octane:start
:
php artisan octane:start --workers=2
Características específicas de Swoole
Como mencioné, Octane viene con un par de características específicas de Swoole, así que echemos un vistazo a ellas, ya que creo que son muy interesantes.
Tareas concurrentes
Octane le permite realizar múltiples tareas al mismo tiempo. Esto significa que se realizarán al mismo tiempo y se devolverán tan pronto como finalicen todas las tareas.
Aquí hay un ejemplo tomado de la documentación de Octane en GitHub:
use App\User;
use App\Server;
use Laravel\Octane\Facades\Octane;
[$users, $servers] = Octane::concurrently([
fn () => User::all(),
fn () => Server::all(),
]);
Entonces, en este ejemplo, obtenemos todos los usuarios y todos los servidores al mismo tiempo. Para aclarar esto, aquí hay otro ejemplo:
Octane::concurrently([
function () {
sleep(0.5);
return 1;
},
function () {
sleep(1);
return 2;
},
]);
Estamos ejecutando dos «tareas» al mismo tiempo y PHP continuará evaluando el código tan pronto como ambas tareas estén terminadas. Una tarea espera 0,5 segundos, la otra espera 1 segundo. Como se están evaluando al mismo tiempo, en dos tareas individuales, PHP esperará exactamente 1 segundo (no 1,5) hasta que ambos resultados estén disponibles. Esta función es una excelente manera de realizar múltiples tareas más pequeñas simultáneamente.
Al igual que la opción --workers
, también puede personalizar la cantidad de --task-workers
que deberían estar disponibles.
Ticks o intervalos
Octane en combinación con Swoole, le permite registrarse ticks
, que son operaciones que se ejecutarán automáticamente en un intervalo determinado. Similar al método setInterval
en JavaScript. Desafortunadamente, no hay forma de detener esos ticks en este momento, pero puede registrarlos dentro de su aplicación de esta manera:
Octane::tick('simple-ticker', fn () => ray('Ticking...'))
->seconds(10);
El caché de Octane
Otra característica nueva de Octane y Swoole es un nuevo controlador de caché. Este controlador de caché, según la documentación oficial, proporciona velocidades de lectura y escritura de hasta 2 millones de operaciones por segundo. Detrás de escena, Swoole almacena en caché los datos en una memoria compartida utilizando Swoole Tables , a las que pueden acceder todos los workers. Sin embargo, cuando el servidor se reinicia , los datos almacenados en caché se vacían, ya que el caché solo se conserva en la memoria.
Para hacer uso de esta caché, puedo hacerlo de la siguiente forma:
Cache::store('octane')->put('framework', 'Laravel', 30);
Otra novedad interesante, que es específica de Swoole y Octane, es la capacidad de un «intervalo de caché». Esto le permite almacenar información en la caché de Octane y actualizar los datos en un intervalo determinado:
use Illuminate\Support\Str;
Cache::store('octane')->interval('random', function () {
return Str::random(10);
}, seconds: 5)
Tablas de Laravel Octane
Basado en la función de Swoole Tables, puede crear sus propias tablas a las que desee acceder dentro de sus aplicaciones de Octane. Estas tablas tienen el mismo beneficio de rendimiento que tendría una caché, ya que le permiten guardar datos de forma estructurada. Sin embargo, tenga en cuenta que todos los datos que almacene dentro de dicha tabla se perderán cuando se reinicie el servidor.
Para configurar una tabla, puede crear una entrada en la sección tables
del archivo de configuración octane.php
:
'tables' => [
'example:1000' => [
'name' => 'string:1000',
'votes' => 'int',
],
],
En este ejemplo, estamos definiendo una tabla llamada example
, que puede contener un máximo de 1.000 registros/filas. La estructura de esta tabla es name
, que es una cadena con una longitud máxima de 1000 y votes
, que es un número entero.
Para escribir datos en esta tabla, podemos hacer uso del método Octane::table
:
use Laravel\Octane\Facades\Octane;
Octane::table('example')->set('a-unique-identifier', [
'name' => 'Marcel Pociot',
'votes' => 1000,
]);
Y para extraer los datos, podemos usar el método get
en la tabla, así:
return Octane::table('example')->get('a-unique-identifier');
Advertencias con Laravel Octane
Hay un par de cosas que debe tener en cuenta cuando desee preparar una aplicación existente para Octane o comenzar a crear una nueva aplicación desde cero.
Dado que Octane mantiene el Framework en la memoria de todos los workers, cosas como todos sus proveedores de servicios de aplicaciones solo se registrarán y arrancarán una vez. Si bien Octane se encarga de restablecer el estado de los paquetes propios, no es posible que Octane restablezca el estado global que podría tener en su propio código de aplicación.
La documentación oficial, que actualmente se puede encontrar en GitHub, contiene algunos de los escenarios más comunes que debe tener en cuenta.
Listeners
Una característica de Octane que aún no se ha documentado es la capacidad de registrar listeners personalizados para que puedas disparar acciones que quieras hacer luego de alguno de los siguientes eventos de Octane:
- WorkerStarting
- RequestReceived
- RequestHandled
- RequestTerminated
- TaskReceived
- TickReceived
- OperationTerminated
- WorkerErrorOccurred
- WorkerStopping
Para adjuntar listeners a estos eventos, puede agregarlos al archivo octane.php
.
Servicio de Warming y Flushing
Cuando se inicia un nuevo worker de Octane, puede especificar una lista de bindings/services de contenedor que desea «warm up» durante el proceso de inicio. Esto significa que, tras el arranque del worker, el contenedor de servicios ya hará que los servicios especificados estén disponibles, de modo que las siguientes solicitudes puedan acceder a ellos inmediatamente.
Octane ya tiene una lista de servicios internos que mantiene caliente durante el proceso de arranque de cada worker, pero puede agregar sus propios servicios a la sección warm
del archivo de configuración octane.php
.
De manera similar, también puede definir una lista de servicios que desea vaciar, antes de que ingrese una nueva solicitud (flushing). Esto puede ser útil para los servicios que se manipulan en el transcurso de una solicitud, que desea restablecer a su estado original cuando entra una nueva solicitud.
Rutas de Octane
Si Octane aún no le otorga suficiente impulso de velocidad, incluso puede exprimirlo un poco más, haciendo uso del sistema de enrutamiento de Octane. Puede definir una ruta de Octane personalizada a través de la facade de Octane de esta manera:
Octane::route('GET', '/fast', function() {
});
Estas rutas son muy rápidas porque omiten por completo el sistema de enrutamiento de Laravel (por lo que estas rutas no proporcionan ningún tipo de middleware), lo que puede ser útil para los endpoints que solo necesitan proporcionar datos realmente rápido.
Dado que el kernel HTTP en Laravel no se está utilizando para estas solicitudes, debe devolver un objeto de respuesta de Symfony usted mismo, como este:
use Symfony\Component\HttpFoundation\Response;
Octane::route('GET', '/faster', function() {
return new Response('Hello from Octane.');
});
Por supuesto, todos los proveedores de servicios están iniciados y disponibles, por lo que aún puede hacer uso de estos servicios, realizar consultas de Eloquent, etc.
Muy bien… entonces, ¿por qué Octane?
Laravel Octane definitivamente le dará a su aplicación Laravel un gran impulso de rendimiento, y a todos nos encantan los aumentos de rendimiento, ¿no es así? ¿Realmente necesitamos este impulso de rendimiento? Bueno, tal vez, creo que depende de la aplicación que esté ejecutando. Pero lo que es más importante para mí, es el hecho de que Laravel está (una vez más) impulsando el estado actual de PHP. Octane no solo es un paquete que requiere al menos PHP 8, sino que también impulsa nuevas y emocionantes características en el mundo de PHP, como corrutinas, ticks y, en general, la mentalidad de servir su propia aplicación utilizando un comando artesanal.
Te esperamos en nuestro canal de Twitch donde estaremos probando Laravel Octane en vivo, seguinos! 👉 https://www.twitch.tv/laraveltip
Excelent!!!!!!!
Muchas gracias por esta publicación. Excelente información. Saludos
Excelente información, muy buen contenido.
Tengo una pregunta… Supongamos que ya tengo una aplicación Laravel funcionando y quisiera probar octane entonces: Tendría que hacer una implementacion de octane y crear las rutas para que mi implementación actual de Laravel acceda a las rutas que he creado en octane? En escencia, existirían un ambiente Laravel y Laravel octane? Es así o se haría de otra forma? Gracias…
Excelente!! gracias por compartir.