Englische Dokumente | 中文文档
LaravelS ist ein sofort einsatzbereiter Adapter zwischen Laravel/Lumen und Swoole
Watch
dieses Repository an, um die neuesten Updates zu erhalten.Integrierter HTTP-/WebSocket-Server
Gemischtes Multi-Port-Protokoll
Benutzerdefinierter Prozess
Speicherresident
Asynchrone Ereignisüberwachung
Asynchrone Aufgabenwarteschlange
Millisekunden-Cronjob
Gemeinsame Komponenten
Anmutig neu laden
Automatisches Neuladen nach Codeänderung
Unterstützt sowohl Laravel als auch Lumen, gute Kompatibilität
Einfach und sofort einsatzbereit
Welches ist das schnellste Webframework?
TechEmpower Framework-Benchmarks
Abhängigkeit | Erfordernis |
---|---|
PHP | >=8.2 Recommend 8.2 |
Swoole | >=5.0 Recommend 5.1.1 |
Laravel/Lumen | >=10 Recommend 10 |
1. Paket über Composer (Packagist) anfordern.
# 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. Registrieren Sie den Dienstanbieter (wählen Sie einen von zwei aus).
Laravel
: In der Datei config/app.php
Laravel 5.5+ supports package discovery automatically, you should skip this step
' providers ' => [
//...
Hhxsv5 LaravelS Illuminate LaravelSServiceProvider::class,
],
Lumen
: in der Datei bootstrap/app.php
$ app -> register ( Hhxsv5 LaravelS Illuminate LaravelSServiceProvider::class);
3.Konfiguration und Binärdateien veröffentlichen.
Nach dem Upgrade von LaravelS müssen Sie es erneut veröffentlichen. Klicken Sie hier, um die Änderungshinweise zu jeder Version anzuzeigen.
php artisan laravels publish
# Configuration: config/laravels.php
# Binary: bin/laravels bin/fswatch bin/inotify
4.Ändern Sie config/laravels.php
: listen_ip, listen_port, siehe Einstellungen.
5. Leistungsoptimierung
Passen Sie die Kernel-Parameter an
Anzahl der Worker: LaravelS verwendet den Synchronous IO
Modus von Swoole. Je größer die Einstellung „ worker_num
ist, desto besser ist die Parallelitätsleistung, aber es führt zu mehr Speichernutzung und Prozesswechsel-Overhead. Wenn eine Anfrage 100 ms dauert, müssen mindestens 100 Worker-Prozesse konfiguriert werden, um eine Parallelität von 1000 QPS bereitzustellen. Die Berechnungsmethode lautet: worker_num = 1000QPS/(1s/1ms) = 100, daher sind inkrementelle Drucktests erforderlich, um die beste worker_num
zu berechnen.
Anzahl der Aufgabenarbeiter
Please read the notices carefully before running
. Wichtige Hinweise (WICHTIG).
php bin/laravels {start|stop|restart|reload|info|help}
.Befehl | Beschreibung |
---|---|
Start | Starten Sie LaravelS und listen Sie die Prozesse mit „ ps -ef|grep laravels “ auf. |
stoppen | Stoppen Sie LaravelS und lösen Sie die Methode onStop des benutzerdefinierten Prozesses aus |
neu starten | Starten Sie LaravelS neu: Stoppen Sie ordnungsgemäß, bevor Sie beginnen. Der Dienst ist unavailable , bis der Startvorgang abgeschlossen ist |
neu laden | Laden Sie alle Task-/Worker-/Timer-Prozesse neu, die Ihre Geschäftscodes enthalten, und lösen Sie die Methode onReload des benutzerdefinierten Prozesses aus. Master-/Manager-Prozesse können NICHT neu geladen werden. Nachdem config/laravels.php geändert haben, müssen Sie zum Neustart only restart aufrufen |
Info | Informationen zur Komponentenversion anzeigen |
helfen | Hilfeinformationen anzeigen |
start
und restart
.Option | Beschreibung |
---|---|
-d|--daemonize | Als Daemon ausführen, überschreibt diese Option die Einstellung swoole.daemonize in laravels.php |
-e|--env | Die Umgebung, in der der Befehl ausgeführt werden soll, z. B. --env=testing verwendet zunächst die Konfigurationsdatei .env.testing Für diese Funktion ist Laravel 5.2+ erforderlich |
-i|--ignore | Ignorieren Sie die Prüfung der PID-Datei des Master-Prozesses |
-x|--x-Version | Die Version (Zweig) des aktuellen Projekts, gespeichert in $_ENV/$_SERVER, Zugriff über $_ENV['X_VERSION'] $_SERVER['X_VERSION'] $request->server->get('X_VERSION') |
Runtime
: start
führt automatisch php artisan laravels config
aus und generiert diese Dateien. Entwickler müssen im Allgemeinen nicht auf sie achten. Es wird empfohlen, sie zu .gitignore
hinzuzufügen.Datei | Beschreibung |
---|---|
storage/laravels.conf | runtime von LaravelS |
storage/laravels.pid | PID-Datei des Master-Prozesses |
storage/laravels-timer-process.pid | PID-Datei des Timer-Prozesses |
storage/laravels-custom-processes.pid | PID-Datei aller benutzerdefinierten Prozesse |
Es wird empfohlen, den Hauptprozess über Supervisord zu überwachen, vorausgesetzt, dass die Option
-d
fehlt undswoole.daemonize
auffalse
gesetzt ist.
[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
Demo.
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 >
Die Abhöradresse des WebSocket-Servers ist dieselbe wie die des HTTP-Servers.
1. Erstellen Sie die WebSocket-Handler-Klasse und implementieren Sie die Schnittstelle WebSocketHandlerInterface
. Der Instant wird beim Start automatisch instanziiert, Sie müssen ihn nicht manuell erstellen.
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.Ändern Sie 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.Verwenden Sie SwooleTable
, um FD und UserId zu binden, optional, Swoole Table Demo. Sie können auch die anderen globalen Speicherdienste wie Redis/Memcached/MySQL verwenden. Beachten Sie jedoch, dass FD möglicherweise zu Konflikten zwischen mehreren Swoole Servers
führt.
4. Mit Nginx zusammenarbeiten (empfohlen)
Siehe WebSocket-Proxy
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. Herzschlag-Einstellung
Herzschlageinstellung von 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 ,
//...
],
Proxy-Lesezeitüberschreitung von Nginx
# Nginx will close the connection if the proxied server does not send data to Nginx in 60 seconds
proxy_read_timeout 60s ;
6.Daten in den Controller übertragen
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 );
}
}
Normalerweise können Sie einige
global/static
Variablen zurücksetzen/zerstören oder das aktuelleRequest/Response
Objekt ändern.
laravels.received_request
Nachdem LaravelS SwooleHttpRequest
an IlluminateHttpRequest
analysiert hat, bevor Laravel's Kernel diese Anfrage verarbeitet.
// 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
Nachdem der Kernel von Laravel die Anfrage bearbeitet hat, bevor LaravelS IlluminateHttpResponse
zu SwooleHttpResponse
analysiert.
// 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
});
Diese Funktion hängt von
AsyncTask
vonSwoole
ab. Sie müssen zunächstswoole.task_worker_num
inconfig/laravels.php
festlegen. Die Leistung der asynchronen Ereignisverarbeitung wird durch die Anzahl der Swoole-Aufgabenprozesse beeinflusst. Sie müssen task_worker_num entsprechend festlegen.
1.Ereignisklasse erstellen.
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. Erstellen Sie eine Listener-Klasse.
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. Feuerereignis.
// 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
Diese Funktion hängt von
AsyncTask
vonSwoole
ab. Sie müssen zunächstswoole.task_worker_num
inconfig/laravels.php
festlegen. Die Leistung der Aufgabenverarbeitung wird durch die Anzahl der Swoole-Aufgabenprozesse beeinflusst. Sie müssen task_worker_num entsprechend festlegen.
1. Aufgabenklasse erstellen.
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. Aufgabe liefern.
// 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
Wrapper-Cron-Job basiert auf Swooles Millisekunden-Timer und ersetzt
Linux
Crontab
.
1.Erstellen Sie eine Cron-Job-Klasse.
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. Cron-Job registrieren.
// 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.Hinweis: Beim Erstellen des Serverclusters werden mehrere Timer gestartet. Sie müssen daher sicherstellen, dass nur ein Timer gestartet wird, um die Ausführung sich wiederholender Aufgaben zu vermeiden.
4.LaravelS v3.4.0
beginnt mit der Unterstützung des Hot-Restart- Timer
Prozesses [Neu laden]. Nachdem LaravelS das SIGUSR1
Signal empfangen hat, wartet es max_wait_time
(Standard 5) Sekunden, um den Prozess zu beenden, dann ruft der Manager
-Prozess den Timer
-Prozess erneut auf.
5.Wenn Sie nur geplante Aufgaben minute-level
verwenden müssen, wird empfohlen Hhxsv5LaravelSIlluminateLaravelScheduleJob
anstelle von Linux Crontab zu aktivieren, damit Sie den Codierungsgewohnheiten der Laravel-Aufgabenplanung folgen und Kernel
konfigurieren können.
// 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 ();
}
Unterstützt über inotify
nur Linux.
1.Installieren Sie die Inotify-Erweiterung.
2.Schalten Sie den Schalter in den Einstellungen ein.
3.Hinweis: Ändern Sie die Datei nur unter Linux
um die Dateiänderungsereignisse zu empfangen. Es wird empfohlen, den neuesten Docker zu verwenden. Landstreicher-Lösung.
Unterstützt über fswatch
OS X/Linux/Windows.
1.Installieren Sie fswatch.
2.Führen Sie den Befehl in Ihrem Projektstammverzeichnis aus.
# Watch current directory
./bin/fswatch
# Watch app directory
./bin/fswatch ./app
Unterstützen Sie Linux über inotifywait
.
1.Innotify-tools installieren.
2.Führen Sie den Befehl in Ihrem Projektstammverzeichnis aus.
# Watch current directory
./bin/inotify
# Watch app directory
./bin/inotify ./app
Wenn die oben genannten Methoden nicht funktionieren, besteht die ultimative Lösung darin, max_request=1,worker_num=1
festzulegen, damit der Worker
-Prozess nach der Verarbeitung einer Anfrage neu gestartet wird. Die Leistung dieser Methode ist sehr schlecht, so only development environment use
.
SwooleServer
in Ihr Projekt /**
* $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. Tabelle definieren, mehrere unterstützen.
Alle definierten Tabellen werden vor dem Start von Swoole erstellt.
// 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.Zugriff auf Table
: Alle Tabelleninstanzen werden an SwooleServer
gebunden, Zugriff über 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 }" );
}
}
Weitere Informationen finden Sie unter Swoole Server AddListener
Damit unser Hauptserver mehr Protokolle als nur Http und WebSocket unterstützt, bringen wir das Feature multi-port mixed protocol
von Swoole in LaravelS ein und nennen es Socket
. Jetzt können Sie problemlos TCP/UDP
-Anwendungen auf Laravel erstellen.
Erstellen Sie Socket
Handler-Klasse und erweitern Sie 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 ' );
}
}
Diese Socket
-Verbindungen nutzen dieselben Arbeitsprozesse wie Ihre HTTP
/ WebSocket
-Verbindungen. Es wird also überhaupt kein Problem sein, wenn Sie Aufgaben liefern, SwooleTable
und sogar Laravel-Komponenten wie DB, Eloquent usw. verwenden möchten. Gleichzeitig können Sie über die Mitgliedereigenschaft swoolePort
direkt auf das Objekt SwooleServerPort
zugreifen.
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');
// }
}
}
}
Registrieren Sie Sockets.
// 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
],
],
Die Heartbeat-Konfiguration kann nur auf dem main server
festgelegt und nicht auf Socket
konfiguriert werden, aber der Socket
erbt die Heartbeat-Konfiguration des main server
.
Für TCP-Sockets werden die Ereignisse onConnect
und onClose
blockiert, wenn dispatch_mode
von Swoole 1/3
ist. Wenn Sie also diese beiden Ereignisse entsperren möchten, setzen Sie bitte dispatch_mode
auf 2/4/5
.
' swoole ' => [
//...
' dispatch_mode ' => 2 ,
//...
];
Prüfen.
TCP: telnet 127.0.0.1 5291
UDP: [Linux] echo "Hello LaravelS" > /dev/udp/127.0.0.1/5292
Registrieren Sie Beispiele für andere Protokolle.
' 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
, d. h. websocket.enable
auf true
setzen. ' 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,
],
],
Swoole Coroutine
Warnung: Die Reihenfolge der Codeausführung in der Coroutine ist nicht in der richtigen Reihenfolge. Die Daten der Anforderungsebene sollten durch die Coroutine-ID isoliert werden. Allerdings gibt es in Laravel/Lumen viele Singleton- und statische Attribute, und die Daten zwischen verschiedenen Anforderungen wirken sich gegenseitig aus, was Unsafe
ist. Wenn es sich beispielsweise bei der Datenbankverbindung um einen Singleton handelt, nutzt dieselbe Datenbankverbindung dieselbe PDO-Ressource. Im synchronen Blockierungsmodus ist dies in Ordnung, im asynchronen Coroutine-Modus funktioniert es jedoch nicht. Jede Abfrage muss unterschiedliche Verbindungen erstellen und den E/A-Status verschiedener Verbindungen beibehalten, was einen Verbindungspool erfordert.
Aktivieren Sie die Coroutine DO NOT
. Nur der benutzerdefinierte Prozess kann die Coroutine verwenden.
Unterstützen Sie Entwickler bei der Erstellung spezieller Arbeitsprozesse für Überwachung, Berichterstellung oder andere spezielle Aufgaben. Siehe addProcess.
Erstellen Sie eine Proccess-Klasse und implementieren Sie 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
}
}
Registrieren Sie TestProcess.
// 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
],
],
Hinweis: Callback() kann nicht beendet werden. Beim Beenden erstellt der Manager-Prozess den Prozess neu.
Beispiel: Daten in einen benutzerdefinierten Prozess schreiben.
// 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
ruft dieApollo
-Konfiguration ab und schreibt sie beim Start in die.env
Datei. Gleichzeitig startetLaravelS
den benutzerdefinierten Prozessapollo
um die Konfiguration zu überwachen und automatischreload
, wenn sich die Konfiguration ändert.
Apollo aktivieren: Fügen Sie die Parameter --enable-apollo
und Apollo zu den Startparametern hinzu.
php bin/laravels start --enable-apollo --apollo-server=http://127.0.0.1:8080 --apollo-app-id=LARAVEL-S-TEST
Unterstützt Hot-Updates (optional).
// 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 (),
Liste der verfügbaren Parameter.
Parameter | Beschreibung | Standard | Demo |
---|---|---|---|
Apollo-Server | Apollo-Server-URL | - | --apollo-server=http://127.0.0.1:8080 |
Apollo-App-ID | Apollo-APP-ID | - | --apollo-app-id=LARAVEL-S-TEST |
Apollo-Namespaces | Der Namespace, zu dem die APP gehört, unterstützt die Angabe mehrerer | Anwendung | --apollo-namespaces=Anwendung --apollo-namespaces=env |
Apollo-Cluster | Der Cluster, zu dem die APP gehört | Standard | --apollo-cluster=default |
apollo-client-ip | IP der aktuellen Instanz, kann auch für die Graustufenveröffentlichung verwendet werden | Lokale Intranet-IP | --apollo-client-ip=10.2.1.83 |
Apollo-Pull-Timeout | Timeout-Zeit (Sekunden) beim Abrufen der Konfiguration | 5 | --apollo-pull-timeout=5 |
apollo-backup-old-env | Ob beim Aktualisieren der Konfigurationsdatei .env die alte Konfigurationsdatei gesichert werden soll | FALSCH | --apollo-backup-old-env |
Unterstützt Prometheus-Überwachung und -Alarm, Grafana zeigt Überwachungsmetriken visuell an. Informationen zur Umgebungskonstruktion von Prometheus und Grafana finden Sie in Docker Compose.
Erfordert die Erweiterung APCu >= 5.0.0, bitte installieren Sie sie mit pecl install apcu
.
Kopieren Sie die Konfigurationsdatei prometheus.php
in das config
Ihres Projekts. Ändern Sie die Konfiguration entsprechend.
# Execute commands in the project root directory
cp vendor/hhxsv5/laravel-s/config/prometheus.php config/
Wenn Ihr Projekt Lumen
ist, müssen Sie auch die Konfiguration $app->configure('prometheus');
manuell laden. in bootstrap/app.php
.
Konfigurieren Sie global
Middleware: Hhxsv5LaravelSComponentsPrometheusRequestMiddleware::class
. Um den Anforderungszeitverbrauch so genau wie möglich zu zählen, muss RequestMiddleware
die first
globale Middleware sein, die vor anderen Middleware platziert werden muss.
Registrieren Sie den ServiceProvider: Hhxsv5LaravelSComponentsPrometheusServiceProvider::class
.
Konfigurieren Sie den CollectorProcess in config/laravels.php
um die Metriken der Swoole Worker/Task/Timer-Prozesse regelmäßig zu sammeln.
' processes ' => Hhxsv5 LaravelS Components Prometheus CollectorProcess:: getDefinition (),
Erstellen Sie die Route zur Ausgabe von Metriken.
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 ]);
});
Schließen Sie die Konfiguration von Prometheus ab und starten Sie es.
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
Starten Sie Grafana und importieren Sie dann Panel-JSON.
Unterstützte Veranstaltungen:
Ereignis | Schnittstelle | Wann ist passiert |
---|---|---|
ServerStart | Hhxsv5LaravelSSwooleEventsServerStartInterface | Tritt auf, wenn der Master-Prozess startet. this event should not handle complex business logic, and can only do some simple work of initialization . |
ServerStop | Hhxsv5LaravelSSwooleEventsServerStopInterface | Tritt auf, wenn der Server normal beendet wird. CANNOT use async or coroutine related APIs in this event . |
WorkerStart | Hhxsv5LaravelSSwooleEventsWorkerStartInterface | Tritt auf, nachdem der Worker-/Task-Prozess gestartet wurde und die Laravel-Initialisierung abgeschlossen wurde. |
WorkerStop | Hhxsv5LaravelSSwooleEventsWorkerStopInterface | Tritt auf, nachdem der Worker-/Task-Prozess normal beendet wurde |
WorkerError | Hhxsv5LaravelSSwooleEventsWorkerErrorInterface | Tritt auf, wenn im Worker-/Task-Prozess eine Ausnahme oder ein schwerwiegender Fehler auftritt |
1.Erstellen Sie eine Ereignisklasse, um die entsprechende Schnittstelle zu implementieren.
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.Konfiguration.
// Edit `config/laravels.php`
' event_handlers ' => [
' ServerStart ' => [ App Events ServerStartEvent::class], // Trigger events in array order
' WorkerStart ' => [ App Events WorkerStartEvent::class],
],
Funktion Berechnen.
1.Ändern Sie bootstrap/app.php
und legen Sie das Speicherverzeichnis fest. Da das Projektverzeichnis schreibgeschützt ist, kann das Verzeichnis /tmp
nur gelesen und geschrieben werden.
$ app -> useStoragePath ( env ( ' APP_STORAGE_PATH ' , ' /tmp/storage ' ));
2.Erstellen Sie ein Shell-Skript laravels_bootstrap
und erteilen Sie 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. Konfigurieren Sie 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
Im FPM-Modus werden Singleton-Instanzen in jeder Anfrage instanziiert und recycelt, Anfragestart => Instanz instanziieren => Anfrageende => recycelte Instanz.
Unter Swoole Server werden alle Singleton-Instanzen im Speicher gehalten, mit einer anderen Lebensdauer als FPM, Anforderungsstart => Instanz instanziieren => Anforderungsende => Singleton-Instanz nicht recyceln. Daher muss der Entwickler den Status der Singleton-Instanzen bei jeder Anfrage beibehalten.
Gängige Lösungen:
Schreiben Sie eine XxxCleaner
Klasse, um den Status des Singleton-Objekts zu bereinigen. Diese Klasse implementiert die Schnittstelle Hhxsv5LaravelSIlluminateCleanersCleanerInterface
und registriert sie dann in cleaners
von laravels.php
.
Status von Singleton-Instanzen durch Middleware
Reset
.
Registrieren Sie ServiceProvider
erneut und fügen Sie XxxServiceProvider
zu register_providers
der Datei laravels.php
hinzu. Damit Singleton-Instanzen bei jeder Anfrage neu initialisiert werden.
Konfigurationsreiniger.
Bekannte Probleme: ein Paket bekannter Probleme und Lösungen.
Protokollierung; Wenn Sie die Ausgabe an die Konsole senden möchten, können Sie stderr
, Log::channel('stderr')->debug('debug message') verwenden.
Laravel Dump Server (Laravel 5.7 wurde standardmäßig integriert).
Leseanforderung durch IlluminateHttpRequest
Objekt, $_ENV ist lesbar, $_SERVER ist teilweise lesbar, $_GET/$_POST/$_FILES/$_COOKIE/$_REQUEST/$_SESSION/$GLOBALS CANNOT USE
.
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 ();
//...
}
Antwort per IlluminateHttpResponse
Objekt, kompatibel mit echo/vardump()/print_r(). Die Funktionen dd()/exit()/die()/header()/setcookie()/http_response_code() CANNOT USE
werden.
public function json ()
{
return response ()-> json ([ ' time ' => time ()])-> header ( ' header1 ' , ' value1 ' )-> withCookie ( ' c1 ' , ' v1 ' );
}
Singleton connection
wird im Speicher gespeichert. Für eine bessere Leistung wird empfohlen, persistent connection
zu aktivieren.
will
immediately
der Trennung automatisch wiederhergestellt. // 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
immediately
nach der Trennung automatisch wiederhergestellt. Bei einem Verbindungsverlust wird eine Ausnahme ausgelöst. Stellen Sie die Verbindung beim nächsten Mal erneut her. Sie müssen jedes Mal sicherstellen, dass SELECT DB
korrekt ist, bevor Sie Redis ausführen. // 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
],
],
Vermeiden Sie die Verwendung globaler Variablen. Bitte reinigen oder setzen Sie sie bei Bedarf manuell zurück.
Das unendliche Anhängen eines Elements an static
/ global
Variable führt zu OOM (Out of Memory).
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 ' );
}
Methode zur Erkennung von Speicherlecks
Ändern Sie config/laravels.php
: worker_num=1, max_request=1000000
. Denken Sie daran, es nach dem Test wieder zu ändern.
Fügen Sie Routing /debug-memory-leak
ohne route middleware
hinzu, um die Speicheränderungen des Worker
-Prozesses zu beobachten.
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 ;
});
Starten Sie LaravelS
und fordern Sie /debug-memory-leak
an, bis diff_mem
kleiner oder gleich Null ist; Wenn diff_mem
immer größer als Null ist, bedeutet dies, dass möglicherweise ein Speicherverlust in Global Middleware
oder Laravel Framework
vorliegt.
Fordern Sie nach Abschluss von Step 3
alternately
die Geschäftsrouten und /debug-memory-leak
an (es wird empfohlen, ab
/ wrk
zu verwenden, um eine große Anzahl von Geschäftsroutenanforderungen zu stellen). Die anfängliche Speicherzunahme ist normal. Wenn diff_mem
nach einer großen Anzahl von Anforderungen für die Geschäftsrouten immer größer als Null ist und curr_mem
weiter zunimmt, besteht eine hohe Wahrscheinlichkeit eines Speicherverlusts. Wenn sich curr_mem
immer innerhalb eines bestimmten Bereichs ändert und nicht weiter ansteigt, ist die Wahrscheinlichkeit eines Speicherverlusts gering.
Wenn Sie das Problem immer noch nicht lösen können, ist max_request die letzte Garantie.
Anpassung der Linux-Kernel-Parameter
Drucktest
PayPal
BTC
Gitee
MIT