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 VCS2. 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
-dfehlt undswoole.daemonizeauffalsegesetzt 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/staticVariablen zurücksetzen/zerstören oder das aktuelleRequest/ResponseObjekt ä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
AsyncTaskvonSwooleab. Sie müssen zunächstswoole.task_worker_numinconfig/laravels.phpfestlegen. 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
AsyncTaskvonSwooleab. Sie müssen zunächstswoole.task_worker_numinconfig/laravels.phpfestlegen. 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
LinuxCrontab.
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 ' );SwooleTable1. 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 ());
}
LaravelSruft dieApollo-Konfiguration ab und schreibt sie beim Start in die.envDatei. Gleichzeitig startetLaravelSden benutzerdefinierten Prozessapolloum 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-TESTUnterstü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: 5sStarten 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