Documentos en inglés | 中文文档
LaravelS es un adaptador listo para usar entre Laravel/Lumen y Swoole
Watch
este repositorio para obtener las últimas actualizaciones.Servidor Http/WebSocket integrado
Protocolo mixto multipuerto
Proceso personalizado
Residente de la memoria
Escucha de eventos asincrónica
Cola de tareas asincrónica
Trabajo cron de milisegundos
Componentes comunes
Recarga con gracia
Recargar automáticamente después de modificar el código
Soporta Laravel/Lumen ambos, buena compatibilidad.
Sencillo y listo para usar
¿Cuál es el framework web más rápido?
Puntos de referencia del marco TechEmpower
Dependencia | Requisito |
---|---|
PHP | >=8.2 Recommend 8.2 |
lana | >=5.0 Recommend 5.1.1 |
Laravel/Lumen | >=10 Recommend 10 |
1.Requerir paquete a través de Composer (packagist).
# PHP >=8.2
composer require " hhxsv5/laravel-s:~3.8.0 "
# PHP >=5.5.9,<=7.4.33
# composer require "hhxsv5/laravel-s:~3.7.0"
# Make sure that your composer.lock file is under the VCS
2.Registrar proveedor de servicios (elija uno de dos).
Laravel
: en el archivo config/app.php
, Laravel 5.5+ supports package discovery automatically, you should skip this step
' providers ' => [
//...
Hhxsv5 LaravelS Illuminate LaravelSServiceProvider::class,
],
Lumen
: en el archivo bootstrap/app.php
$ app -> register ( Hhxsv5 LaravelS Illuminate LaravelSServiceProvider::class);
3.Publicar configuración y binarios.
Después de actualizar LaravelS, debes volver a publicar; haga clic aquí para ver las notas de cambio de cada versión.
php artisan laravels publish
# Configuration: config/laravels.php
# Binary: bin/laravels bin/fswatch bin/inotify
4. Cambie config/laravels.php
: listening_ip, listening_port, consulte Configuración.
5.Ajuste del rendimiento
Ajustar los parámetros del kernel
Número de trabajadores: LaravelS utiliza el modo Synchronous IO
de Swoole. Cuanto mayor sea la configuración worker_num
, mejor será el rendimiento de concurrencia, pero provocará un mayor uso de memoria y una sobrecarga de conmutación de procesos. Si una solicitud tarda 100 ms, para proporcionar una simultaneidad de 1000 QPS, se deben configurar al menos 100 procesos de trabajo. El método de cálculo es: número_trabajador = 1000QPS/(1s/1ms) = 100, por lo que se necesita una prueba de presión incremental para calcular el mejor worker_num
.
Número de trabajadores de tareas
Please read the notices carefully before running
. Avisos importantes (IMPORTANTE).
php bin/laravels {start|stop|restart|reload|info|help}
.Dominio | Descripción |
---|---|
comenzar | Inicie LaravelS, enumere los procesos con " ps -ef|grep laravels " |
detener | Detenga LaravelS y active el método onStop del proceso personalizado |
Reanudar | Reinicie LaravelS: deténgase con gracia antes de comenzar; El servicio no está unavailable hasta que se complete el inicio. |
recargar | Vuelva a cargar todos los procesos de Tarea/Trabajador/Temporizador que contengan sus códigos comerciales y active el método onReload del proceso personalizado; NO PUEDE recargar los procesos Maestro/Administrador. Después de modificar config/laravels.php , only tienes que llamar restart para reiniciar |
información | Mostrar información de la versión del componente |
ayuda | Mostrar información de ayuda |
start
y restart
.Opción | Descripción |
---|---|
-d|--endemoniar | Ejecutar como demonio, esta opción anulará la configuración de swoole.daemonize en laravels.php |
-e|--env | El entorno en el que debe ejecutarse el comando, como --env=testing utilizará el archivo de configuración .env.testing en primer lugar, esta característica requiere Laravel 5.2+ |
-i|--ignorar | Ignorar la comprobación del archivo PID del proceso maestro |
-x|--x-versión | La versión (rama) del proyecto actual, almacenada en $_ENV/$_SERVER, acceso a través de $_ENV['X_VERSION'] $_SERVER['X_VERSION'] $request->server->get('X_VERSION') |
Runtime
: start
ejecutará automáticamente php artisan laravels config
y generará estos archivos, los desarrolladores generalmente no necesitan prestarles atención, se recomienda agregarlos a .gitignore
.Archivo | Descripción |
---|---|
almacenamiento/laravels.conf | Archivo de configuración de runtime de LaravelS |
almacenamiento/laravels.pid | Archivo PID del proceso maestro |
almacenamiento/laravels-timer-process.pid | Archivo PID del proceso del Temporizador |
almacenamiento/laravels-procesos-personalizados.pid | Archivo PID de todos los procesos personalizados. |
Se recomienda supervisar el proceso principal a través de Supervisord, la premisa es sin la opción
-d
y configurarswoole.daemonize
enfalse
.
[program:laravel-s-test]
directory=/var/www/laravel-s-test
command=/usr/local/bin/php bin/laravels start -i
numprocs=1
autostart=true
autorestart=true
startretries=3
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/supervisor/%(program_name)s.log
Manifestación.
gzip on ;
gzip_min_length 1024 ;
gzip_comp_level 2 ;
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml;
gzip_vary on ;
gzip_disable "msie6" ;
upstream swoole {
# Connect IP:Port
server 127.0.0.1:5200 weight=5 max_fails=3 fail_timeout=30s;
# Connect UnixSocket Stream file, tips: put the socket file in the /dev/shm directory to get better performance
#server unix:/yourpath/laravel-s-test/storage/laravels.sock weight=5 max_fails=3 fail_timeout=30s;
#server 192.168.1.1:5200 weight=3 max_fails=3 fail_timeout=30s;
#server 192.168.1.2:5200 backup;
keepalive 16;
}
server {
listen 80 ;
# Don't forget to bind the host
server_name laravels.com;
root /yourpath/laravel-s-test/public;
access_log /yourpath/log/nginx/ $server_name .access.log main ;
autoindex off ;
index index.html index.htm;
# Nginx handles the static resources(recommend enabling gzip), LaravelS handles the dynamic resource.
location / {
try_files $uri @laravels;
}
# Response 404 directly when request the PHP file, to avoid exposing public/*.php
#location ~* .php$ {
# return 404;
#}
location @laravels {
# proxy_connect_timeout 60s;
# proxy_send_timeout 60s;
# proxy_read_timeout 120s;
proxy_http_version 1.1 ;
proxy_set_header Connection "" ;
proxy_set_header X-Real-IP $remote_addr ;
proxy_set_header X-Real-PORT $remote_port ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;
proxy_set_header Host $http_host ;
proxy_set_header Scheme $scheme ;
proxy_set_header Server-Protocol $server_protocol ;
proxy_set_header Server-Name $server_name ;
proxy_set_header Server-Addr $server_addr ;
proxy_set_header Server-Port $server_port ;
# "swoole" is the upstream
proxy_pass http://swoole;
}
}
LoadModule proxy_module /yourpath/modules/mod_proxy.so
LoadModule proxy_balancer_module /yourpath/modules/mod_proxy_balancer.so
LoadModule lbmethod_byrequests_module /yourpath/modules/mod_lbmethod_byrequests.so
LoadModule proxy_http_module /yourpath/modules/mod_proxy_http.so
LoadModule slotmem_shm_module /yourpath/modules/mod_slotmem_shm.so
LoadModule rewrite_module /yourpath/modules/mod_rewrite.so
LoadModule remoteip_module /yourpath/modules/mod_remoteip.so
LoadModule deflate_module /yourpath/modules/mod_deflate.so
< IfModule deflate_module>
SetOutputFilter DEFLATE
DeflateCompressionLevel 2
AddOutputFilterByType DEFLATE text/html text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml
</ IfModule >
< VirtualHost *:80>
# Don't forget to bind the host
ServerName www.laravels.com
ServerAdmin [email protected]
DocumentRoot /yourpath/laravel-s-test/public;
DirectoryIndex index.html index.htm
< Directory "/">
AllowOverride None
Require all granted
</ Directory >
RemoteIPHeader X-Forwarded-For
ProxyRequests Off
ProxyPreserveHost On
< Proxy balancer://laravels>
BalancerMember http://192.168.1.1:5200 loadfactor=7
# BalancerMember http://192.168.1.2:5200 loadfactor=3
# BalancerMember http://192.168.1.3:5200 loadfactor=1 status=+H
ProxySet lbmethod=byrequests
</ Proxy >
# ProxyPass / balancer://laravels/
# ProxyPassReverse / balancer://laravels/
# Apache handles the static resources, LaravelS handles the dynamic resource.
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://laravels %{REQUEST_URI} [P,L]
ErrorLog ${APACHE_LOG_DIR}/www.laravels.com.error.log
CustomLog ${APACHE_LOG_DIR}/www.laravels.com.access.log combined
</ VirtualHost >
La dirección de escucha de WebSocket Server es la misma que la del servidor Http.
1.Cree la clase WebSocket Handler e implemente la interfaz WebSocketHandlerInterface
. El instante se crea automáticamente cuando se inicia, no es necesario crearlo manualmente.
namespace App Services ;
use Hhxsv5 LaravelS Swoole WebSocketHandlerInterface ;
use Swoole Http Request ;
use Swoole Http Response ;
use Swoole WebSocket Frame ;
use Swoole WebSocket Server ;
/**
* @see https://www.swoole.co.uk/docs/modules/swoole-websocket-server
*/
class WebSocketService implements WebSocketHandlerInterface
{
// Declare constructor without parameters
public function __construct ()
{
}
// public function onHandShake(Request $request, Response $response)
// {
// Custom handshake: https://www.swoole.co.uk/docs/modules/swoole-websocket-server-on-handshake
// The onOpen event will be triggered automatically after a successful handshake
// }
public function onOpen ( Server $ server , Request $ request )
{
// Before the onOpen event is triggered, the HTTP request to establish the WebSocket has passed the Laravel route,
// so Laravel's Request, Auth information are readable, Session is readable and writable, but only in the onOpen event.
// Log::info('New WebSocket connection', [$request->fd, request()->all(), session()->getId(), session('xxx'), session(['yyy' => time()])]);
// The exceptions thrown here will be caught by the upper layer and recorded in the Swoole log. Developers need to try/catch manually.
$ server -> push ( $ request -> fd , ' Welcome to LaravelS ' );
}
public function onMessage ( Server $ server , Frame $ frame )
{
// Log::info('Received message', [$frame->fd, $frame->data, $frame->opcode, $frame->finish]);
// The exceptions thrown here will be caught by the upper layer and recorded in the Swoole log. Developers need to try/catch manually.
$ server -> push ( $ frame -> fd , date ( ' Y-m-d H:i:s ' ));
}
public function onClose ( Server $ server , $ fd , $ reactorId )
{
// The exceptions thrown here will be caught by the upper layer and recorded in the Swoole log. Developers need to try/catch manually.
}
}
2.Modificar config/laravels.php
.
// ...
' websocket ' => [
' enable ' => true , // Note: set enable to true
' handler ' => App Services WebSocketService::class,
],
' swoole ' => [
//...
// Must set dispatch_mode in (2, 4, 5), see https://www.swoole.co.uk/docs/modules/swoole-server/configuration
' dispatch_mode ' => 2 ,
//...
],
// ...
3.Utilice SwooleTable
para vincular FD y UserId, opcional, demostración de Swoole Table. También puede utilizar otros servicios de almacenamiento global, como Redis/Memcached/MySQL, pero tenga cuidado de que FD pueda entrar en conflicto entre varios Swoole Servers
.
4.Cooperar con Nginx (recomendado)
Consulte el proxy WebSocket
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream swoole {
# Connect IP:Port
server 127.0.0.1:5200 weight=5 max_fails=3 fail_timeout=30s;
# Connect UnixSocket Stream file, tips: put the socket file in the /dev/shm directory to get better performance
#server unix:/yourpath/laravel-s-test/storage/laravels.sock weight=5 max_fails=3 fail_timeout=30s;
#server 192.168.1.1:5200 weight=3 max_fails=3 fail_timeout=30s;
#server 192.168.1.2:5200 backup;
keepalive 16;
}
server {
listen 80 ;
# Don't forget to bind the host
server_name laravels.com;
root /yourpath/laravel-s-test/public;
access_log /yourpath/log/nginx/ $server_name .access.log main ;
autoindex off ;
index index.html index.htm;
# Nginx handles the static resources(recommend enabling gzip), LaravelS handles the dynamic resource.
location / {
try_files $uri @laravels;
}
# Response 404 directly when request the PHP file, to avoid exposing public/*.php
#location ~* .php$ {
# return 404;
#}
# Http and WebSocket are concomitant, Nginx identifies them by "location"
# !!! The location of WebSocket is "/ws"
# Javascript: var ws = new WebSocket("ws://laravels.com/ws");
location =/ws {
# proxy_connect_timeout 60s;
# proxy_send_timeout 60s;
# proxy_read_timeout: Nginx will close the connection if the proxied server does not send data to Nginx in 60 seconds; At the same time, this close behavior is also affected by heartbeat setting of Swoole.
# proxy_read_timeout 60s;
proxy_http_version 1.1 ;
proxy_set_header X-Real-IP $remote_addr ;
proxy_set_header X-Real-PORT $remote_port ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;
proxy_set_header Host $http_host ;
proxy_set_header Scheme $scheme ;
proxy_set_header Server-Protocol $server_protocol ;
proxy_set_header Server-Name $server_name ;
proxy_set_header Server-Addr $server_addr ;
proxy_set_header Server-Port $server_port ;
proxy_set_header Upgrade $http_upgrade ;
proxy_set_header Connection $connection_upgrade ;
proxy_pass http://swoole;
}
location @laravels {
# proxy_connect_timeout 60s;
# proxy_send_timeout 60s;
# proxy_read_timeout 60s;
proxy_http_version 1.1 ;
proxy_set_header Connection "" ;
proxy_set_header X-Real-IP $remote_addr ;
proxy_set_header X-Real-PORT $remote_port ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;
proxy_set_header Host $http_host ;
proxy_set_header Scheme $scheme ;
proxy_set_header Server-Protocol $server_protocol ;
proxy_set_header Server-Name $server_name ;
proxy_set_header Server-Addr $server_addr ;
proxy_set_header Server-Port $server_port ;
proxy_pass http://swoole;
}
}
5.Configuración del latido del corazón
Configuración del latido del corazón de Swoole
// config/laravels.php
' swoole ' => [
//...
// All connections are traversed every 60 seconds. If a connection does not send any data to the server within 600 seconds, the connection will be forced to close.
' heartbeat_idle_time ' => 600 ,
' heartbeat_check_interval ' => 60 ,
//...
],
Tiempo de espera de lectura de proxy de Nginx
# Nginx will close the connection if the proxied server does not send data to Nginx in 60 seconds
proxy_read_timeout 60s ;
6.Insertar datos en el controlador
namespace App Http Controllers ;
class TestController extends Controller
{
public function push ()
{
$ fd = 1 ; // Find fd by userId from a map [userId=>fd].
/**@var SwooleWebSocketServer $swoole */
$ swoole = app ( ' swoole ' );
$ success = $ swoole -> push ( $ fd , ' Push data to fd#1 in Controller ' );
var_dump ( $ success );
}
}
Por lo general, puede restablecer/destruir algunas variables
global/static
, o cambiar el objetoRequest/Response
actual.
laravels.received_request
Después de que LaravelS analizó SwooleHttpRequest
para IlluminateHttpRequest
, antes de que el kernel de Laravel maneje esta solicitud.
// Edit file `app/Providers/EventServiceProvider.php`, add the following code into method `boot`
// If no variable $events, you can also call Facade Event::listen().
$ events -> listen ( ' laravels.received_request ' , function ( Illuminate Http Request $ req , $ app ) {
$ req -> query -> set ( ' get_key ' , ' hhxsv5 ' ); // Change query of request
$ req -> request -> set ( ' post_key ' , ' hhxsv5 ' ); // Change post of request
});
laravels.generated_response
Después de que el kernel de Laravel manejó la solicitud, antes de que LaravelS analice IlluminateHttpResponse
en SwooleHttpResponse
.
// Edit file `app/Providers/EventServiceProvider.php`, add the following code into method `boot`
// If no variable $events, you can also call Facade Event::listen().
$ events -> listen ( ' laravels.generated_response ' , function ( Illuminate Http Request $ req , Symfony Component HttpFoundation Response $ rsp , $ app ) {
$ rsp -> headers -> set ( ' header-key ' , ' hhxsv5 ' ); // Change header of response
});
Esta característica depende de
AsyncTask
deSwoole
, primero debe configurarswoole.task_worker_num
enconfig/laravels.php
. El rendimiento del procesamiento de eventos asincrónicos está influenciado por la cantidad de procesos de tareas de Swoole; debe configurar task_worker_num de manera adecuada.
1.Crear clase de evento.
use Hhxsv5 LaravelS Swoole Task Event ;
class TestEvent extends Event
{
protected $ listeners = [
// Listener list
TestListener1::class,
// TestListener2::class,
];
private $ data ;
public function __construct ( $ data )
{
$ this -> data = $ data ;
}
public function getData ()
{
return $ this -> data ;
}
}
2.Crear una clase de oyente.
use Hhxsv5 LaravelS Swoole Task Event ;
use Hhxsv5 LaravelS Swoole Task Task ;
use Hhxsv5 LaravelS Swoole Task Listener ;
class TestListener1 extends Listener
{
public function handle ( Event $ event )
{
Log:: info ( __CLASS__ . ' :handle start ' , [ $ event -> getData ()]);
sleep ( 2 ); // Simulate the slow codes
// Deliver task in CronJob, but NOT support callback finish() of task.
// Note: Modify task_ipc_mode to 1 or 2 in config/laravels.php, see https://www.swoole.co.uk/docs/modules/swoole-server/configuration
$ ret = Task:: deliver ( new TestTask ( ' task data ' ));
var_dump ( $ ret );
// The exceptions thrown here will be caught by the upper layer and recorded in the Swoole log. Developers need to try/catch manually.
// return false; // Stop propagating this event to subsequent listeners
}
}
3.Evento de incendio.
// Create instance of event and fire it, "fire" is asynchronous.
use Hhxsv5 LaravelS Swoole Task Event ;
$ event = new TestEvent ( ' event data ' );
// $event->delay(10); // Delay 10 seconds to fire event
// $event->setTries(3); // When an error occurs, try 3 times in total
$ success = Event:: fire ( $ event );
var_dump ( $ success ); // Return true if sucess, otherwise false
Esta característica depende de
AsyncTask
deSwoole
, primero debe configurarswoole.task_worker_num
enconfig/laravels.php
. El rendimiento del procesamiento de tareas está influenciado por la cantidad de procesos de tareas de Swoole; debe configurar task_worker_num de manera adecuada.
1.Crear clase de tarea.
use Hhxsv5 LaravelS Swoole Task Task ;
class TestTask extends Task
{
private $ data ;
private $ result ;
public function __construct ( $ data )
{
$ this -> data = $ data ;
}
// The logic of task handling, run in task process, CAN NOT deliver task
public function handle ()
{
Log:: info ( __CLASS__ . ' :handle start ' , [ $ this -> data ]);
sleep ( 2 ); // Simulate the slow codes
// The exceptions thrown here will be caught by the upper layer and recorded in the Swoole log. Developers need to try/catch manually.
$ this -> result = ' the result of ' . $ this -> data ;
}
// Optional, finish event, the logic of after task handling, run in worker process, CAN deliver task
public function finish ()
{
Log:: info ( __CLASS__ . ' :finish start ' , [ $ this -> result ]);
Task:: deliver ( new TestTask2 ( ' task2 data ' )); // Deliver the other task
}
}
2.Entregar tarea.
// Create instance of TestTask and deliver it, "deliver" is asynchronous.
use Hhxsv5 LaravelS Swoole Task Task ;
$ task = new TestTask ( ' task data ' );
// $task->delay(3);// delay 3 seconds to deliver task
// $task->setTries(3); // When an error occurs, try 3 times in total
$ ret = Task:: deliver ( $ task );
var_dump ( $ ret ); // Return true if sucess, otherwise false
"El trabajo cron del contenedor se basa en el temporizador de milisegundos de Swoole, reemplaza
Crontab
Linux
".
1.Cree una clase de trabajo cron.
namespace App Jobs Timer ;
use App Tasks TestTask ;
use Swoole Coroutine ;
use Hhxsv5 LaravelS Swoole Task Task ;
use Hhxsv5 LaravelS Swoole Timer CronJob ;
class TestCronJob extends CronJob
{
protected $ i = 0 ;
// !!! The `interval` and `isImmediate` of cron job can be configured in two ways(pick one of two): one is to overload the corresponding method, and the other is to pass parameters when registering cron job.
// --- Override the corresponding method to return the configuration: begin
public function interval ()
{
return 1000 ; // Run every 1000ms
}
public function isImmediate ()
{
return false ; // Whether to trigger `run` immediately after setting up
}
// --- Override the corresponding method to return the configuration: end
public function run ()
{
Log:: info ( __METHOD__ , [ ' start ' , $ this -> i , microtime ( true )]);
// do something
// sleep(1); // Swoole < 2.1
Coroutine:: sleep ( 1 ); // Swoole>=2.1 Coroutine will be automatically created for run().
$ this -> i ++;
Log:: info ( __METHOD__ , [ ' end ' , $ this -> i , microtime ( true )]);
if ( $ this -> i >= 10 ) { // Run 10 times only
Log:: info ( __METHOD__ , [ ' stop ' , $ this -> i , microtime ( true )]);
$ this -> stop (); // Stop this cron job, but it will run again after restart/reload.
// Deliver task in CronJob, but NOT support callback finish() of task.
// Note: Modify task_ipc_mode to 1 or 2 in config/laravels.php, see https://www.swoole.co.uk/docs/modules/swoole-server/configuration
$ ret = Task:: deliver ( new TestTask ( ' task data ' ));
var_dump ( $ ret );
}
// The exceptions thrown here will be caught by the upper layer and recorded in the Swoole log. Developers need to try/catch manually.
}
}
2.Registrar el trabajo cron.
// Register cron jobs in file "config/laravels.php"
[
// ...
' timer ' => [
' enable ' => true , // Enable Timer
' jobs ' => [ // The list of cron job
// Enable LaravelScheduleJob to run `php artisan schedule:run` every 1 minute, replace Linux Crontab
// Hhxsv5LaravelSIlluminateLaravelScheduleJob::class,
// Two ways to configure parameters:
// [AppJobsTimerTestCronJob::class, [1000, true]], // Pass in parameters when registering
App Jobs Timer TestCronJob::class, // Override the corresponding method to return the configuration
],
' max_wait_time ' => 5 , // Max waiting time of reloading
// Enable the global lock to ensure that only one instance starts the timer when deploying multiple instances. This feature depends on Redis, please see https://laravel.com/docs/7.x/redis
' global_lock ' => false ,
' global_lock_key ' => config ( ' app.name ' , ' Laravel ' ),
],
// ...
];
3.Nota: iniciará varios temporizadores cuando se cree el clúster de servidores, por lo que debe asegurarse de iniciar solo un temporizador para evitar ejecutar tareas repetitivas.
4.LaravelS v3.4.0
comienza a admitir el proceso Timer
de reinicio en caliente [Recargar]. Después de que LaravelS recibe la señal SIGUSR1
, espera max_wait_time
(predeterminado 5) segundos para finalizar el proceso, luego el proceso Manager
iniciará el proceso Timer
nuevamente.
5. Si solo necesita usar tareas programadas minute-level
, se recomienda habilitar Hhxsv5LaravelSIlluminateLaravelScheduleJob
en lugar de Linux Crontab, para que pueda seguir los hábitos de codificación de la programación de tareas de Laravel y configurar Kernel
.
// app/Console/Kernel.php
protected function schedule ( Schedule $ schedule )
{
// runInBackground() will start a new child process to execute the task. This is asynchronous and will not affect the execution timing of other tasks.
$ schedule -> command (TestCommand::class)-> runInBackground ()-> everyMinute ();
}
A través de inotify
, solo es compatible con Linux.
1.Instale la extensión inotify.
2.Encienda el interruptor en Configuración.
3.Aviso: Modifique el archivo solo en Linux
para recibir los eventos de cambio de archivo. Se recomienda utilizar la última versión de Docker. Solución vagabunda.
A través de fswatch
, admite OS X/Linux/Windows.
1.Instale fswatch.
2.Ejecute el comando en el directorio raíz de su proyecto.
# Watch current directory
./bin/fswatch
# Watch app directory
./bin/fswatch ./app
A través de inotifywait
, admite Linux.
1.Instale las herramientas de notificación.
2.Ejecute el comando en el directorio raíz de su proyecto.
# Watch current directory
./bin/inotify
# Watch app directory
./bin/inotify ./app
Cuando los métodos anteriores no funcionan, la solución definitiva: establecer max_request=1,worker_num=1
, para que el proceso Worker
se reinicie después de procesar una solicitud. El rendimiento de este método es muy pobre, so only development environment use
.
SwooleServer
en su proyecto /**
* $swoole is the instance of `SwooleWebSocketServer` if enable WebSocket server, otherwise `SwooleHttpServer`
* @var SwooleWebSocketServer|SwooleHttpServer $swoole
*/
$ swoole = app ( ' swoole ' );
var_dump ( $ swoole -> stats ());
$ swoole -> push ( $ fd , ' Push WebSocket message ' );
SwooleTable
1.Definir tabla, admite múltiples.
Todas las tablas definidas se crearán antes de que comience Swoole.
// in file "config/laravels.php"
[
// ...
' swoole_tables ' => [
// Scene:bind UserId & FD in WebSocket
' ws ' => [ // The Key is table name, will add suffix "Table" to avoid naming conflicts. Here defined a table named "wsTable"
' size ' => 102400 , // The max size
' column ' => [ // Define the columns
[ ' name ' => ' value ' , ' type ' => Swoole Table:: TYPE_INT , ' size ' => 8 ],
],
],
//...Define the other tables
],
// ...
];
2.Acceso a Table
: todas las instancias de la tabla estarán vinculadas a SwooleServer
, se accederá mediante app('swoole')->xxxTable
.
namespace App Services ;
use Hhxsv5 LaravelS Swoole WebSocketHandlerInterface ;
use Swoole Http Request ;
use Swoole WebSocket Frame ;
use Swoole WebSocket Server ;
class WebSocketService implements WebSocketHandlerInterface
{
/**@var SwooleTable $wsTable */
private $ wsTable ;
public function __construct ()
{
$ this -> wsTable = app ( ' swoole ' )-> wsTable ;
}
// Scene:bind UserId & FD in WebSocket
public function onOpen ( Server $ server , Request $ request )
{
// var_dump(app('swoole') === $server);// The same instance
/**
* Get the currently logged in user
* This feature requires that the path to establish a WebSocket connection go through middleware such as Authenticate.
* E.g:
* Browser side: var ws = new WebSocket("ws://127.0.0.1:5200/ws");
* Then the /ws route in Laravel needs to add the middleware like Authenticate.
* Route::get('/ws', function () {
* // Respond any content with status code 200
* return 'websocket';
* })->middleware(['auth']);
*/
// $user = Auth::user();
// $userId = $user ? $user->id : 0; // 0 means a guest user who is not logged in
$ userId = mt_rand ( 1000 , 10000 );
// if (!$userId) {
// // Disconnect the connections of unlogged users
// $server->disconnect($request->fd);
// return;
// }
$ this -> wsTable -> set ( ' uid: ' . $ userId , [ ' value ' => $ request -> fd ]); // Bind map uid to fd
$ this -> wsTable -> set ( ' fd: ' . $ request -> fd , [ ' value ' => $ userId ]); // Bind map fd to uid
$ server -> push ( $ request -> fd , " Welcome to LaravelS # { $ request -> fd }" );
}
public function onMessage ( Server $ server , Frame $ frame )
{
// Broadcast
foreach ( $ this -> wsTable as $ key => $ row ) {
if ( strpos ( $ key , ' uid: ' ) === 0 && $ server -> isEstablished ( $ row [ ' value ' ])) {
$ content = sprintf ( ' Broadcast: new message "%s" from #%d ' , $ frame -> data , $ frame -> fd );
$ server -> push ( $ row [ ' value ' ], $ content );
}
}
}
public function onClose ( Server $ server , $ fd , $ reactorId )
{
$ uid = $ this -> wsTable -> get ( ' fd: ' . $ fd );
if ( $ uid !== false ) {
$ this -> wsTable -> del ( ' uid: ' . $ uid [ ' value ' ]); // Unbind uid map
}
$ this -> wsTable -> del ( ' fd: ' . $ fd ); // Unbind fd map
$ server -> push ( $ fd , " Goodbye # { $ fd }" );
}
}
Para obtener más información, consulte Swoole Server AddListener
Para que nuestro servidor principal admita más protocolos, no solo Http y WebSocket, incorporamos la función multi-port mixed protocol
de Swoole en LaravelS y lo llamamos Socket
. Ahora, puede crear aplicaciones TCP/UDP
fácilmente sobre Laravel.
Cree una clase de controlador Socket
y extienda Hhxsv5LaravelSSwooleSocket{TcpSocket|UdpSocket|Http|WebSocket}
.
namespace App Sockets ;
use Hhxsv5 LaravelS Swoole Socket TcpSocket ;
use Swoole Server ;
class TestTcpSocket extends TcpSocket
{
public function onConnect ( Server $ server , $ fd , $ reactorId )
{
Log:: info ( ' New TCP connection ' , [ $ fd ]);
$ server -> send ( $ fd , ' Welcome to LaravelS. ' );
}
public function onReceive ( Server $ server , $ fd , $ reactorId , $ data )
{
Log:: info ( ' Received data ' , [ $ fd , $ data ]);
$ server -> send ( $ fd , ' LaravelS: ' . $ data );
if ( $ data === " quit rn" ) {
$ server -> send ( $ fd , ' LaravelS: bye ' . PHP_EOL );
$ server -> close ( $ fd );
}
}
public function onClose ( Server $ server , $ fd , $ reactorId )
{
Log:: info ( ' Close TCP connection ' , [ $ fd ]);
$ server -> send ( $ fd , ' Goodbye ' );
}
}
Estas conexiones Socket
comparten los mismos procesos de trabajo con sus conexiones HTTP
/ WebSocket
. Por lo tanto, no será un problema en absoluto si desea realizar tareas, use SwooleTable
, incluso componentes de Laravel como DB, Eloquent, etc. Al mismo tiempo, puede acceder al objeto SwooleServerPort
directamente mediante la propiedad del miembro swoolePort
.
public function onReceive ( Server $ server , $ fd , $ reactorId , $ data )
{
$ port = $ this -> swoolePort ; // Get the `SwooleServerPort` object
}
namespace App Http Controllers ;
class TestController extends Controller
{
public function test ()
{
/**@var SwooleHttpServer|SwooleWebSocketServer $swoole */
$ swoole = app ( ' swoole ' );
// $swoole->ports: Traverse all Port objects, https://www.swoole.co.uk/docs/modules/swoole-server/multiple-ports
$ port = $ swoole -> ports [ 0 ]; // Get the `SwooleServerPort` object, $port[0] is the port of the main server
foreach ( $ port -> connections as $ fd ) { // Traverse all connections
// $swoole->send($fd, 'Send tcp message');
// if($swoole->isEstablished($fd)) {
// $swoole->push($fd, 'Send websocket message');
// }
}
}
}
Registrar enchufes.
// Edit `config/laravels.php`
//...
' sockets ' => [
[
' host ' => ' 127.0.0.1 ' ,
' port ' => 5291 ,
' type ' => SWOOLE_SOCK_TCP , // Socket type: SWOOLE_SOCK_TCP/SWOOLE_SOCK_TCP6/SWOOLE_SOCK_UDP/SWOOLE_SOCK_UDP6/SWOOLE_UNIX_DGRAM/SWOOLE_UNIX_STREAM
' settings ' => [ // Swoole settings:https://www.swoole.co.uk/docs/modules/swoole-server-methods#swoole_server-addlistener
' open_eof_check ' => true ,
' package_eof ' => "rn" ,
],
' handler ' => App Sockets TestTcpSocket::class,
' enable ' => true , // whether to enable, default true
],
],
Acerca de la configuración de latidos, solo se puede configurar en el main server
y no se puede configurar en Socket
, pero Socket
hereda la configuración de latidos del main server
.
Para el socket TCP, los eventos onConnect
y onClose
se bloquearán cuando dispatch_mode
de Swoole sea 1/3
, por lo que si desea desbloquear estos dos eventos, configure dispatch_mode
en 2/4/5
.
' swoole ' => [
//...
' dispatch_mode ' => 2 ,
//...
];
Prueba.
TCP: telnet 127.0.0.1 5291
UDP: [Linux] echo "Hello LaravelS" > /dev/udp/127.0.0.1/5292
Registrar ejemplo de otros protocolos.
' sockets ' => [
[
' host ' => ' 0.0.0.0 ' ,
' port ' => 5292 ,
' type ' => SWOOLE_SOCK_UDP ,
' settings ' => [
' open_eof_check ' => true ,
' package_eof ' => "rn" ,
],
' handler ' => App Sockets TestUdpSocket::class,
],
],
' sockets ' => [
[
' host ' => ' 0.0.0.0 ' ,
' port ' => 5293 ,
' type ' => SWOOLE_SOCK_TCP ,
' settings ' => [
' open_http_protocol ' => true ,
],
' handler ' => App Sockets TestHttp::class,
],
],
turn on WebSocket
, es decir, configurar websocket.enable
en true
. ' sockets ' => [
[
' host ' => ' 0.0.0.0 ' ,
' port ' => 5294 ,
' type ' => SWOOLE_SOCK_TCP ,
' settings ' => [
' open_http_protocol ' => true ,
' open_websocket_protocol ' => true ,
],
' handler ' => App Sockets TestWebSocket::class,
],
],
Corrutina Swoole
Advertencia: el orden de ejecución del código en la corrutina está desordenado. Los datos del nivel de solicitud deben estar aislados por el ID de la rutina. Sin embargo, hay muchos atributos estáticos y únicos en Laravel/Lumen, los datos entre diferentes solicitudes se afectarán entre sí, es Unsafe
. Por ejemplo, la conexión de la base de datos es única, la misma conexión de la base de datos comparte el mismo recurso PDO. Esto está bien en el modo de bloqueo sincrónico, pero no funciona en el modo de rutina asíncrono. Cada consulta necesita crear conexiones diferentes y mantener el estado de IO de diferentes conexiones, lo que requiere un grupo de conexiones.
DO NOT
habilite la corrutina, solo el proceso personalizado puede usar la corrutina.
Ayude a los desarrolladores a crear procesos de trabajo especiales para monitorear, generar informes u otras tareas especiales. Consulte agregarProceso.
Crea la clase Proccess, implementa CustomProcessInterface.
namespace App Processes ;
use App Tasks TestTask ;
use Hhxsv5 LaravelS Swoole Process CustomProcessInterface ;
use Hhxsv5 LaravelS Swoole Task Task ;
use Swoole Coroutine ;
use Swoole Http Server ;
use Swoole Process ;
class TestProcess implements CustomProcessInterface
{
/**
* @var bool Quit tag for Reload updates
*/
private static $ quit = false ;
public static function callback ( Server $ swoole , Process $ process )
{
// The callback method cannot exit. Once exited, Manager process will automatically create the process
while (! self :: $ quit ) {
Log:: info ( ' Test process: running ' );
// sleep(1); // Swoole < 2.1
Coroutine:: sleep ( 1 ); // Swoole>=2.1: Coroutine & Runtime will be automatically enabled for callback(). Pay attention to the compatibility between the components used and the coroutines. If they are not compatible, only some coroutines can be enabled, such as: SwooleRuntime::enableCoroutine(SWOOLE_HOOK_TCP | SWOOLE_HOOK_SLEEP | SWOOLE_HOOK_FILE);
// Deliver task in custom process, but NOT support callback finish() of task.
// Note: Modify task_ipc_mode to 1 or 2 in config/laravels.php, see https://www.swoole.co.uk/docs/modules/swoole-server/configuration
$ ret = Task:: deliver ( new TestTask ( ' task data ' ));
var_dump ( $ ret );
// The upper layer will catch the exception thrown in the callback and record it in the Swoole log, and then this process will exit. The Manager process will re-create the process after 3 seconds, so developers need to try/catch to catch the exception by themselves to avoid frequent process creation.
// throw new Exception('an exception');
}
}
// Requirements: LaravelS >= v3.4.0 & callback() must be async non-blocking program.
public static function onReload ( Server $ swoole , Process $ process )
{
// Stop the process...
// Then end process
Log:: info ( ' Test process: reloading ' );
self :: $ quit = true ;
// $process->exit(0); // Force exit process
}
// Requirements: LaravelS >= v3.7.4 & callback() must be async non-blocking program.
public static function onStop ( Server $ swoole , Process $ process )
{
// Stop the process...
// Then end process
Log:: info ( ' Test process: stopping ' );
self :: $ quit = true ;
// $process->exit(0); // Force exit process
}
}
Registre el proceso de prueba.
// Edit `config/laravels.php`
// ...
' processes ' => [
' test ' => [ // Key name is process name
' class ' => App Processes TestProcess::class,
' redirect ' => false , // Whether redirect stdin/stdout, true or false
' pipe ' => 0 , // The type of pipeline, 0: no pipeline 1: SOCK_STREAM 2: SOCK_DGRAM
' enable ' => true , // Whether to enable, default true
//'num' => 3 // To create multiple processes of this class, default is 1
//'queue' => [ // Enable message queue as inter-process communication, configure empty array means use default parameters
// 'msg_key' => 0, // The key of the message queue. Default: ftok(__FILE__, 1).
// 'mode' => 2, // Communication mode, default is 2, which means contention mode
// 'capacity' => 8192, // The length of a single message, is limited by the operating system kernel parameters. The default is 8192, and the maximum is 65536
//],
//'restart_interval' => 5, // After the process exits abnormally, how many seconds to wait before restarting the process, default 5 seconds
],
],
Nota: La devolución de llamada() no puede salir. Si sale, el proceso Manager volverá a crear el proceso.
Ejemplo: escribir datos en un proceso personalizado.
// config/laravels.php
' processes ' => [
' test ' => [
' class ' => App Processes TestProcess::class,
' redirect ' => false ,
' pipe ' => 1 ,
],
],
// app/Processes/TestProcess.php
public static function callback ( Server $ swoole , Process $ process )
{
while ( $ data = $ process -> read ()) {
Log:: info ( ' TestProcess: read data ' , [ $ data ]);
$ process -> write ( ' TestProcess: ' . $ data );
}
}
// app/Http/Controllers/TestController.php
public function testProcessWrite ()
{
/**@var SwooleProcess[] $process */
$ customProcesses = Hhxsv5 LaravelS LaravelS:: getCustomProcesses ();
$ process = $ customProcesses [ ' test ' ];
$ process -> write ( ' TestController: write data ' . time ());
var_dump ( $ process -> read ());
}
LaravelS
extraerá la configuraciónApollo
y la escribirá en el archivo.env
al iniciar. Al mismo tiempo,LaravelS
iniciará el proceso personalizadoapollo
para monitorear la configuración yreload
automáticamente cuando la configuración cambie.
Habilite Apollo: agregue los parámetros --enable-apollo
y Apollo a los parámetros de inicio.
php bin/laravels start --enable-apollo --apollo-server=http://127.0.0.1:8080 --apollo-app-id=LARAVEL-S-TEST
Admite actualizaciones en caliente (opcional).
// Edit `config/laravels.php`
' processes ' => Hhxsv5 LaravelS Components Apollo Process:: getDefinition (),
// When there are other custom process configurations
' processes ' => [
' test ' => [
' class ' => App Processes TestProcess::class,
' redirect ' => false ,
' pipe ' => 1 ,
],
// ...
] + Hhxsv5 LaravelS Components Apollo Process:: getDefinition (),
Lista de parámetros disponibles.
Parámetro | Descripción | Por defecto | Manifestación |
---|---|---|---|
servidor-apolo | URL del servidor Apolo | - | --servidor-apollo=http://127.0.0.1:8080 |
ID-de-aplicación-apolo | ID de la aplicación Apolo | - | --apollo-app-id=PRUEBA-S-LARAVEL |
espacios de nombres apolo | El espacio de nombres al que pertenece la aplicación, admite especificar los múltiples | solicitud | --apollo-namespaces=aplicación --apollo-namespaces=env |
cúmulo-apolo | El cluster al que pertenece la APP | por defecto | --apollo-cluster=predeterminado |
ip-cliente-apolo | La IP de la instancia actual también se puede utilizar para la publicación en escala de grises. | IP de intranet local | --apollo-cliente-ip=10.2.1.83 |
tiempo de espera de extracción de apolo | Tiempo de espera (segundos) al extraer la configuración | 5 | --apollo-pull-timeout=5 |
apollo-backup-old-env | Si se debe hacer una copia de seguridad del archivo de configuración anterior al actualizar el archivo de configuración .env | FALSO | --apollo-backup-antiguo-env |
Admite monitoreo y alarma de Prometheus, Grafana ve visualmente las métricas de monitoreo. Consulte Docker Compose para conocer la construcción del entorno de Prometheus y Grafana.
Requiere extensión APCu >= 5.0.0, instálela mediante pecl install apcu
.
Copie el archivo de configuración prometheus.php
al directorio config
de su proyecto. Modifique la configuración según corresponda.
# Execute commands in the project root directory
cp vendor/hhxsv5/laravel-s/config/prometheus.php config/
Si su proyecto es Lumen
, también necesita cargar manualmente la configuración $app->configure('prometheus');
en bootstrap/app.php
.
Configure el middleware global
: Hhxsv5LaravelSComponentsPrometheusRequestMiddleware::class
. Para contar el consumo de tiempo de solicitud con la mayor precisión posible, RequestMiddleware
debe ser el first
middleware global y debe colocarse delante de otros middleware.
Registre el proveedor de servicios: Hhxsv5LaravelSComponentsPrometheusServiceProvider::class
.
Configure CollectorProcess en config/laravels.php
para recopilar las métricas de los procesos Swoole Worker/Task/Timer con regularidad.
' processes ' => Hhxsv5 LaravelS Components Prometheus CollectorProcess:: getDefinition (),
Cree la ruta para generar métricas.
use Hhxsv5 LaravelS Components Prometheus Exporter ;
Route:: get ( ' /actuator/prometheus ' , function () {
$ result = app (Exporter::class)-> render ();
return response ( $ result , 200 , [ ' Content-Type ' => Exporter:: REDNER_MIME_TYPE ]);
});
Complete la configuración de Prometheus e inícielo.
global :
scrape_interval : 5s
scrape_timeout : 5s
evaluation_interval : 30s
scrape_configs :
- job_name : laravel-s-test
honor_timestamps : true
metrics_path : /actuator/prometheus
scheme : http
follow_redirects : true
static_configs :
- targets :
- 127.0.0.1:5200 # The ip and port of the monitored service
# Dynamically discovered using one of the supported service-discovery mechanisms
# https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config
# - job_name: laravels-eureka
# honor_timestamps: true
# scrape_interval: 5s
# metrics_path: /actuator/prometheus
# scheme: http
# follow_redirects: true
# eureka_sd_configs:
# - server: http://127.0.0.1:8080/eureka
# follow_redirects: true
# refresh_interval: 5s
Inicie Grafana, luego importe el panel json.
Eventos soportados:
Evento | Interfaz | cuando paso |
---|---|---|
Inicio del servidor | Hhxsv5LaravelSSwooleEventsServerStartInterface | Ocurre cuando se inicia el proceso Maestro. this event should not handle complex business logic, and can only do some simple work of initialization . |
Parada del servidor | Hhxsv5LaravelSSwooleEventsServerStopInterface | Ocurre cuando el servidor sale normalmente, CANNOT use async or coroutine related APIs in this event . |
TrabajadorInicio | Hhxsv5LaravelSSwooleEventsWorkerStartInterface | Ocurre después de que se inicia el proceso Trabajador/Tarea y se completa la inicialización de Laravel. |
Parada del trabajador | Hhxsv5LaravelSSwooleEventsWorkerStopInterface | Ocurre después de que el proceso Trabajador/Tarea sale normalmente |
Error de trabajador | Hhxsv5LaravelSSwooleEventsWorkerErrorInterface | Ocurre cuando ocurre una excepción o un error fatal en el proceso Trabajador/Tarea |
1.Cree una clase de evento para implementar la interfaz correspondiente.
namespace App Events ;
use Hhxsv5 LaravelS Swoole Events ServerStartInterface ;
use Swoole Atomic ;
use Swoole Http Server ;
class ServerStartEvent implements ServerStartInterface
{
public function __construct ()
{
}
public function handle ( Server $ server )
{
// Initialize a global counter (available across processes)
$ server -> atomicCount = new Atomic ( 2233 );
// Invoked in controller: app('swoole')->atomicCount->get();
}
}
namespace App Events ;
use Hhxsv5 LaravelS Swoole Events WorkerStartInterface ;
use Swoole Http Server ;
class WorkerStartEvent implements WorkerStartInterface
{
public function __construct ()
{
}
public function handle ( Server $ server , $ workerId )
{
// Initialize a database connection pool
// DatabaseConnectionPool::init();
}
}
2.Configuración.
// Edit `config/laravels.php`
' event_handlers ' => [
' ServerStart ' => [ App Events ServerStartEvent::class], // Trigger events in array order
' WorkerStart ' => [ App Events WorkerStartEvent::class],
],
Función Computar.
1.Modifique bootstrap/app.php
y configure el directorio de almacenamiento. Debido a que el directorio del proyecto es de solo lectura, el directorio /tmp
solo se puede leer y escribir.
$ app -> useStoragePath ( env ( ' APP_STORAGE_PATH ' , ' /tmp/storage ' ));
2.Cree un script de shell laravels_bootstrap
y otorgue executable permission
.
#! /usr/bin/env bash
set +e
# Create storage-related directories
mkdir -p /tmp/storage/app/public
mkdir -p /tmp/storage/framework/cache
mkdir -p /tmp/storage/framework/sessions
mkdir -p /tmp/storage/framework/testing
mkdir -p /tmp/storage/framework/views
mkdir -p /tmp/storage/logs
# Set the environment variable APP_STORAGE_PATH, please make sure it's the same as APP_STORAGE_PATH in .env
export APP_STORAGE_PATH=/tmp/storage
# Start LaravelS
php bin/laravels start
3.Configurar template.xml
.
ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
laravel-s-demo:
Type: 'Aliyun::Serverless::Service'
Properties:
Description: 'LaravelS Demo for Serverless'
fc-laravel-s:
Type: 'Aliyun::Serverless::Function'
Properties:
Handler: laravels.handler
Runtime: custom
MemorySize: 512
Timeout: 30
CodeUri: ./
InstanceConcurrency: 10
EnvironmentVariables:
BOOTSTRAP_FILE: laravels_bootstrap
En el modo FPM, las instancias singleton se crearán y reciclarán en cada solicitud, inicio de solicitud => instancia de instancia => fin de solicitud => instancia reciclada.
En Swoole Server, todas las instancias singleton se mantendrán en la memoria, con una vida útil diferente a la de FPM, inicio de solicitud => crear una instancia => fin de la solicitud => no reciclar la instancia singleton. Por lo tanto, es necesario que el desarrollador mantenga el estado de las instancias únicas en cada solicitud.
Soluciones comunes:
Escriba una clase XxxCleaner
para limpiar el estado del objeto singleton. Esta clase implementa la interfaz Hhxsv5LaravelSIlluminateCleanersCleanerInterface
y luego la registra en cleaners
de laravels.php
.
Reset
el estado de las instancias singleton mediante Middleware
.
Vuelva a registrar ServiceProvider
, agregue XxxServiceProvider
en register_providers
del archivo laravels.php
. Para reinicializar las instancias singleton en cada solicitud Consulte.
Limpiadores de configuración.
Problemas conocidos: un paquete de problemas y soluciones conocidos.
Explotación florestal; si desea enviar mensajes a la consola, puede usar stderr
, Log::channel('stderr')->debug('mensaje de depuración').
Laravel Dump Server (Laravel 5.7 se ha integrado de forma predeterminada).
Solicitud de lectura por objeto IlluminateHttpRequest
, $_ENV es legible, $_SERVER es parcialmente legible, CANNOT USE
$_GET/$_POST/$_FILES/$_COOKIE/$_REQUEST/$_SESSION/$GLOBALS.
public function form ( Illuminate Http Request $ request )
{
$ name = $ request -> input ( ' name ' );
$ all = $ request -> all ();
$ sessionId = $ request -> cookie ( ' sessionId ' );
$ photo = $ request -> file ( ' photo ' );
// Call getContent() to get the raw POST body, instead of file_get_contents('php://input')
$ rawContent = $ request -> getContent ();
//...
}
Responda mediante el objeto IlluminateHttpResponse
, compatible con echo/vardump()/print_r(), CANNOT USE
las funciones dd()/exit()/die()/header()/setcookie()/http_response_code().
public function json ()
{
return response ()-> json ([ ' time ' => time ()])-> header ( ' header1 ' , ' value1 ' )-> withCookie ( ' c1 ' , ' v1 ' );
}
Singleton connection
residirá en la memoria; se recomienda activar persistent connection
para un mejor rendimiento.
will
volverá a conectar automáticamente immediately
después de desconectarse. // config/database.php
' connections ' => [
' my_conn ' => [
' driver ' => ' mysql ' ,
' host ' => env ( ' DB_MY_CONN_HOST ' , ' localhost ' ),
' port ' => env ( ' DB_MY_CONN_PORT ' , 3306 ),
' database ' => env ( ' DB_MY_CONN_DATABASE ' , ' forge ' ),
' username ' => env ( ' DB_MY_CONN_USERNAME ' , ' forge ' ),
' password ' => env ( ' DB_MY_CONN_PASSWORD ' , '' ),
' charset ' => ' utf8mb4 ' ,
' collation ' => ' utf8mb4_unicode_ci ' ,
' prefix ' => '' ,
' strict ' => false ,
' options ' => [
// Enable persistent connection
PDO :: ATTR_PERSISTENT => true ,
],
],
],
won't
volverá a conectar automáticamente immediately
después de desconectarse y generará una excepción sobre la conexión perdida, vuelva a conectarse la próxima vez. Debe asegurarse de SELECT DB
correctamente antes de operar Redis cada vez. // config/database.php
' redis ' => [
' client ' => env ( ' REDIS_CLIENT ' , ' phpredis ' ), // It is recommended to use phpredis for better performance.
' default ' => [
' host ' => env ( ' REDIS_HOST ' , ' localhost ' ),
' password ' => env ( ' REDIS_PASSWORD ' , null ),
' port ' => env ( ' REDIS_PORT ' , 6379 ),
' database ' => 0 ,
' persistent ' => true , // Enable persistent connection
],
],
Evite el uso de variables globales. Si es necesario, límpielos o reinícielos manualmente.
Agregar infinitamente elementos a una variable static
/ global
conducirá a OOM (sin memoria).
class Test
{
public static $ array = [];
public static $ string = '' ;
}
// Controller
public function test ( Request $ req )
{
// Out of Memory
Test:: $ array [] = $ req -> input ( ' param1 ' );
Test:: $ string .= $ req -> input ( ' param2 ' );
}
Método de detección de fugas de memoria
Modifique config/laravels.php
: worker_num=1, max_request=1000000
, recuerde volver a cambiarlo después de la prueba;
Agregue enrutamiento /debug-memory-leak
sin route middleware
para observar los cambios de memoria del proceso Worker
;
Route:: get ( ' /debug-memory-leak ' , function () {
global $ previous ;
$ current = memory_get_usage ();
$ stats = [
' prev_mem ' => $ previous ,
' curr_mem ' => $ current ,
' diff_mem ' => $ current - $ previous ,
];
$ previous = $ current ;
return $ stats ;
});
Inicie LaravelS
y solicite /debug-memory-leak
hasta que diff_mem
sea menor o igual a cero; si diff_mem
es siempre mayor que cero, significa que puede haber una pérdida de memoria en Global Middleware
o Laravel Framework
;
Después de completar Step 3
, solicite alternately
las rutas comerciales y /debug-memory-leak
(se recomienda usar ab
/ wrk
para realizar una gran cantidad de solicitudes de rutas comerciales), el aumento inicial de memoria es normal. Después de una gran cantidad de solicitudes para las rutas comerciales, si diff_mem
es siempre mayor que cero y curr_mem
continúa aumentando, existe una alta probabilidad de pérdida de memoria; Si curr_mem
siempre cambia dentro de un cierto rango y no continúa aumentando, existe una baja probabilidad de pérdida de memoria.
Si aún no puedes solucionarlo, max_request es la última garantía.
Ajuste de parámetros del kernel de Linux
Prueba de presión
PayPal
btc
Casa rural
MIT