英語ドキュメント | 中文档
LaravelS は、Laravel/Lumen と Swoole の間のすぐに使えるアダプターです
Watch
ください。内蔵HTTP/WebSocketサーバー
マルチポート混合プロトコル
カスタムプロセス
メモリ常駐
非同期イベントのリスニング
非同期タスクキュー
ミリ秒 cron ジョブ
共通コンポーネント
正常にリロードする
コードを変更した後に自動的にリロードする
Laravel/Lumen 両方をサポート、優れた互換性
シンプルですぐに使える
最も速い Web フレームワークはどれですか?
TechEmpower フレームワークのベンチマーク
依存 | 要件 |
---|---|
PHP | >=8.2 Recommend 8.2 |
スウール | >=5.0 Recommend 5.1.1 |
Laravel/ルーメン | >=10 Recommend 10 |
1.Composer(packagist)経由でパッケージを要求します。
# PHP >=8.2
composer require " hhxsv5/laravel-s:~3.8.0 "
# PHP >=5.5.9,<=7.4.33
# composer require "hhxsv5/laravel-s:~3.7.0"
# Make sure that your composer.lock file is under the VCS
2.サービスプロバイダーを登録します(2つのうち1つを選択します)。
Laravel
: config/app.php
ファイルでは、 Laravel 5.5+ supports package discovery automatically, you should skip this step
' providers ' => [
//...
Hhxsv5 LaravelS Illuminate LaravelSServiceProvider::class,
],
Lumen
: bootstrap/app.php
ファイル内
$ app -> register ( Hhxsv5 LaravelS Illuminate LaravelSServiceProvider::class);
3.構成とバイナリを公開します。
LaravelS をアップグレードした後、再公開する必要があります。各バージョンの変更点を確認するには、ここをクリックしてください。
php artisan laravels publish
# Configuration: config/laravels.php
# Binary: bin/laravels bin/fswatch bin/inotify
config/laravels.php
を変更します: listen_ip、listen_port、設定を参照してください。
5.パフォーマンスチューニング
カーネルパラメータを調整する
ワーカーの数: LaravelS は Swoole のSynchronous IO
モードを使用しますworker_num
設定が大きいほど同時実行パフォーマンスは向上しますが、メモリ使用量とプロセス切り替えのオーバーヘッドが増加します。 1 つのリクエストに 100 ミリ秒かかる場合、1000QPS の同時実行性を実現するには、少なくとも 100 個のワーカー プロセスを構成する必要があります。計算方法は次のとおりです: worker_num = 1000QPS/(1s/1ms) = 100 したがって、最適なworker_num
計算するには増分圧力テストが必要です。
タスクワーカーの数
重要なお知らせ(IMPORTANT)
Please read the notices carefully before running
。
php bin/laravels {start|stop|restart|reload|info|help}
。指示 | 説明 |
---|---|
始める | LaravelSを起動し、「 ps -ef|grep laravels 」でプロセスを一覧表示します。 |
停止 | LaravelSを停止し、カスタムプロセスのonStop メソッドをトリガーします。 |
再起動 | LaravelS を再起動します。開始する前に正常に停止します。起動が完了するまでサービスはunavailable |
リロード | ビジネス コードを含むすべてのタスク/ワーカー/タイマー プロセスをリロードし、カスタム プロセスのonReload メソッドをトリガーします。マスター/マネージャー プロセスをリロードすることはできません。 config/laravels.php 変更した後、再起動するにはrestart 呼び出すonly です。 |
情報 | コンポーネントのバージョン情報を表示する |
ヘルプ | ヘルプ情報を表示する |
start
およびrestart
のブート オプション。オプション | 説明 |
---|---|
-d|--デーモン化 | デーモンとして実行します。このオプションは、 laravels.php のswoole.daemonize 設定をオーバーライドします。 |
-e|--env | --env=testing などのコマンドを実行する環境では、まず構成ファイル.env.testing が使用されます。この機能には Laravel 5.2 以降が必要です。 |
-i|--無視する | マスタープロセスのPIDファイルのチェックを無視する |
-x|--x-バージョン | $_ENV/$_SERVER に保存されている現在のプロジェクトのバージョン (ブランチ)。 $_ENV['X_VERSION'] $_SERVER['X_VERSION'] $request->server->get('X_VERSION') |
Runtime
ファイル: start
自動的にphp artisan laravels config
を実行し、これらのファイルを生成します。開発者は通常、それらに注意を払う必要はありません。それらを.gitignore
に追加することをお勧めします。ファイル | 説明 |
---|---|
ストレージ/laravels.conf | LaravelSのruntime 設定ファイル |
ストレージ/laravels.pid | マスタープロセスのPIDファイル |
storage/laravels-timer-process.pid | タイマープロセスのPIDファイル |
storage/laravels-custom-processes.pid | すべてのカスタム プロセスの PID ファイル |
Supervisord を通じてメインプロセスを監視することをお勧めします。前提として、オプション
-d
は使用せず、swoole.daemonize
false
に設定します。
[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
デモ。
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 >
WebSocket サーバーのリスニング アドレスは、HTTP サーバーと同じです。
1. WebSocket Handler クラスを作成し、インターフェイスWebSocketHandlerInterface
を実装します。インスタントは起動時に自動的にインスタンス化されるため、手動で作成する必要はありません。
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. 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. SwooleTable
を使用して FD と UserId をバインドします (オプション、Swoole Table デモ)。 Redis/Memcached/MySQL などの他のグローバル ストレージ サービスも使用できますが、FD が複数のSwoole Servers
間で競合する可能性があることに注意してください。
4.Nginxとの連携(推奨)
WebSocketプロキシを参照
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream swoole {
# Connect IP:Port
server 127.0.0.1:5200 weight=5 max_fails=3 fail_timeout=30s;
# Connect UnixSocket Stream file, tips: put the socket file in the /dev/shm directory to get better performance
#server unix:/yourpath/laravel-s-test/storage/laravels.sock weight=5 max_fails=3 fail_timeout=30s;
#server 192.168.1.1:5200 weight=3 max_fails=3 fail_timeout=30s;
#server 192.168.1.2:5200 backup;
keepalive 16;
}
server {
listen 80 ;
# Don't forget to bind the host
server_name laravels.com;
root /yourpath/laravel-s-test/public;
access_log /yourpath/log/nginx/ $server_name .access.log main ;
autoindex off ;
index index.html index.htm;
# Nginx handles the static resources(recommend enabling gzip), LaravelS handles the dynamic resource.
location / {
try_files $uri @laravels;
}
# Response 404 directly when request the PHP file, to avoid exposing public/*.php
#location ~* .php$ {
# return 404;
#}
# Http and WebSocket are concomitant, Nginx identifies them by "location"
# !!! The location of WebSocket is "/ws"
# Javascript: var ws = new WebSocket("ws://laravels.com/ws");
location =/ws {
# proxy_connect_timeout 60s;
# proxy_send_timeout 60s;
# proxy_read_timeout: Nginx will close the connection if the proxied server does not send data to Nginx in 60 seconds; At the same time, this close behavior is also affected by heartbeat setting of Swoole.
# proxy_read_timeout 60s;
proxy_http_version 1.1 ;
proxy_set_header X-Real-IP $remote_addr ;
proxy_set_header X-Real-PORT $remote_port ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;
proxy_set_header Host $http_host ;
proxy_set_header Scheme $scheme ;
proxy_set_header Server-Protocol $server_protocol ;
proxy_set_header Server-Name $server_name ;
proxy_set_header Server-Addr $server_addr ;
proxy_set_header Server-Port $server_port ;
proxy_set_header Upgrade $http_upgrade ;
proxy_set_header Connection $connection_upgrade ;
proxy_pass http://swoole;
}
location @laravels {
# proxy_connect_timeout 60s;
# proxy_send_timeout 60s;
# proxy_read_timeout 60s;
proxy_http_version 1.1 ;
proxy_set_header Connection "" ;
proxy_set_header X-Real-IP $remote_addr ;
proxy_set_header X-Real-PORT $remote_port ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;
proxy_set_header Host $http_host ;
proxy_set_header Scheme $scheme ;
proxy_set_header Server-Protocol $server_protocol ;
proxy_set_header Server-Name $server_name ;
proxy_set_header Server-Addr $server_addr ;
proxy_set_header Server-Port $server_port ;
proxy_pass http://swoole;
}
}
5.ハートビート設定
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 ,
//...
],
Nginxのプロキシ読み取りタイムアウト
# Nginx will close the connection if the proxied server does not send data to Nginx in 60 seconds
proxy_read_timeout 60s ;
6.コントローラーにデータをプッシュする
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 );
}
}
通常、一部の
global/static
変数をリセット/破棄したり、現在のRequest/Response
オブジェクトを変更したりできます。
laravels.received_request
LaravelS がSwooleHttpRequest
IlluminateHttpRequest
に解析した後、Laravel のカーネルがこのリクエストを処理する前。
// 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
Laravelのカーネルがリクエストを処理した後、LaravelSがIlluminateHttpResponse
SwooleHttpResponse
に解析する前。
// Edit file `app/Providers/EventServiceProvider.php`, add the following code into method `boot`
// If no variable $events, you can also call Facade Event::listen().
$ events -> listen ( ' laravels.generated_response ' , function ( Illuminate Http Request $ req , Symfony Component HttpFoundation Response $ rsp , $ app ) {
$ rsp -> headers -> set ( ' header-key ' , ' hhxsv5 ' ); // Change header of response
});
この機能は
Swoole
のAsyncTask
に依存しているため、最初にconfig/laravels.php
でswoole.task_worker_num
を設定する必要があります。非同期イベント処理のパフォーマンスはSwooleタスクのプロセス数に影響されるため、task_worker_numを適切に設定する必要があります。
1.イベントクラスを作成します。
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.リスナークラスを作成します。
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.火災イベント。
// 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
この機能は
Swoole
のAsyncTask
に依存しているため、最初にconfig/laravels.php
でswoole.task_worker_num
を設定する必要があります。タスク処理のパフォーマンスはSwooleタスクのプロセス数に影響されるため、task_worker_numを適切に設定する必要があります。
1.タスククラスを作成します。
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.タスクを配信します。
// 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
Swoole のミリ秒タイマーに基づくラッパー cron ジョブは、
Linux
Crontab
を置き換えます。
1.cronジョブクラスを作成します。
namespace App Jobs Timer ;
use App Tasks TestTask ;
use Swoole Coroutine ;
use Hhxsv5 LaravelS Swoole Task Task ;
use Hhxsv5 LaravelS Swoole Timer CronJob ;
class TestCronJob extends CronJob
{
protected $ i = 0 ;
// !!! The `interval` and `isImmediate` of cron job can be configured in two ways(pick one of two): one is to overload the corresponding method, and the other is to pass parameters when registering cron job.
// --- Override the corresponding method to return the configuration: begin
public function interval ()
{
return 1000 ; // Run every 1000ms
}
public function isImmediate ()
{
return false ; // Whether to trigger `run` immediately after setting up
}
// --- Override the corresponding method to return the configuration: end
public function run ()
{
Log:: info ( __METHOD__ , [ ' start ' , $ this -> i , microtime ( true )]);
// do something
// sleep(1); // Swoole < 2.1
Coroutine:: sleep ( 1 ); // Swoole>=2.1 Coroutine will be automatically created for run().
$ this -> i ++;
Log:: info ( __METHOD__ , [ ' end ' , $ this -> i , microtime ( true )]);
if ( $ this -> i >= 10 ) { // Run 10 times only
Log:: info ( __METHOD__ , [ ' stop ' , $ this -> i , microtime ( true )]);
$ this -> stop (); // Stop this cron job, but it will run again after restart/reload.
// Deliver task in CronJob, but NOT support callback finish() of task.
// Note: Modify task_ipc_mode to 1 or 2 in config/laravels.php, see https://www.swoole.co.uk/docs/modules/swoole-server/configuration
$ ret = Task:: deliver ( new TestTask ( ' task data ' ));
var_dump ( $ ret );
}
// The exceptions thrown here will be caught by the upper layer and recorded in the Swoole log. Developers need to try/catch manually.
}
}
2.cronジョブを登録します。
// Register cron jobs in file "config/laravels.php"
[
// ...
' timer ' => [
' enable ' => true , // Enable Timer
' jobs ' => [ // The list of cron job
// Enable LaravelScheduleJob to run `php artisan schedule:run` every 1 minute, replace Linux Crontab
// Hhxsv5LaravelSIlluminateLaravelScheduleJob::class,
// Two ways to configure parameters:
// [AppJobsTimerTestCronJob::class, [1000, true]], // Pass in parameters when registering
App Jobs Timer TestCronJob::class, // Override the corresponding method to return the configuration
],
' max_wait_time ' => 5 , // Max waiting time of reloading
// Enable the global lock to ensure that only one instance starts the timer when deploying multiple instances. This feature depends on Redis, please see https://laravel.com/docs/7.x/redis
' global_lock ' => false ,
' global_lock_key ' => config ( ' app.name ' , ' Laravel ' ),
],
// ...
];
3.注: サーバー クラスターを構築するときに複数のタイマーが起動されるため、反復的なタスクの実行を避けるために、必ず 1 つのタイマーのみを起動するようにする必要があります。
4.LaravelS v3.4.0
はホットリスタート[リロード] Timer
プロセスのサポートを開始します。 LaravelS がSIGUSR1
シグナルを受信した後、プロセスが終了するまでmax_wait_time
(デフォルトは 5) 秒待機し、その後、 Manager
プロセスが再びTimer
プロセスを起動します。
5. minute-level
スケジュールされたタスクのみを使用する必要がある場合は、Linux Crontab の代わりにHhxsv5LaravelSIlluminateLaravelScheduleJob
を有効にすることをお勧めします。これにより、Laravel タスクのスケジュールのコーディング習慣に従い、 Kernel
を設定できます。
// app/Console/Kernel.php
protected function schedule ( Schedule $ schedule )
{
// runInBackground() will start a new child process to execute the task. This is asynchronous and will not affect the execution timing of other tasks.
$ schedule -> command (TestCommand::class)-> runInBackground ()-> everyMinute ();
}
inotify
経由では、Linux のみをサポートします。
1.inotify 拡張機能をインストールします。
2.設定でスイッチをオンにします。
3.注意: ファイル変更イベントを受信するには、 Linux
でのみファイルを変更してください。最新の Docker を使用することをお勧めします。ベイグラントソリューション。
fswatch
経由で、OS X/Linux/Windows をサポートします。
1.fswatchをインストールします。
2.プロジェクトのルートディレクトリでコマンドを実行します。
# Watch current directory
./bin/fswatch
# Watch app directory
./bin/fswatch ./app
inotifywait
経由で、Linux をサポートします。
1.inotify ツールをインストールします。
2.プロジェクトのルートディレクトリでコマンドを実行します。
# Watch current directory
./bin/inotify
# Watch app directory
./bin/inotify ./app
上記の方法が機能しない場合の最終的な解決策は、 max_request=1,worker_num=1
を設定して、リクエストの処理後にWorker
プロセスが再起動されるようにすることです。このメソッドのパフォーマンスは非常に低いso only development environment use
。
SwooleServer
のインスタンスを取得します /**
* $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.テーブルを定義し、複数をサポートします。
定義されたすべてのテーブルは、Swoole の開始前に作成されます。
// in file "config/laravels.php"
[
// ...
' swoole_tables ' => [
// Scene:bind UserId & FD in WebSocket
' ws ' => [ // The Key is table name, will add suffix "Table" to avoid naming conflicts. Here defined a table named "wsTable"
' size ' => 102400 , // The max size
' column ' => [ // Define the columns
[ ' name ' => ' value ' , ' type ' => Swoole Table:: TYPE_INT , ' size ' => 8 ],
],
],
//...Define the other tables
],
// ...
];
2. Table
のアクセス: すべてのテーブル インスタンスはSwooleServer
にバインドされ、 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 }" );
}
}
詳細については、「Swoole Server AddListener」を参照してください。
メインサーバーが Http と WebSocket だけでなく、より多くのプロトコルをサポートできるようにするために、Swoole の機能multi-port mixed protocol
LaravelS に導入し、これにSocket
名前を付けます。 Laravel 上にTCP/UDP
アプリケーションを簡単に構築できるようになりました。
Socket
ハンドラー クラスを作成し、 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 ' );
}
}
これらのSocket
接続は、 HTTP
/ WebSocket
接続と同じワーカー プロセスを共有します。したがって、タスクを配信したい場合は、 SwooleTable
使用するだけでなく、DB や Eloquent などの Laravel コンポーネントを使用することもまったく問題ありません。同時に、メンバープロパティswoolePort
によってSwooleServerPort
オブジェクトに直接アクセスできます。
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');
// }
}
}
}
ソケットを登録します。
// 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
],
],
ハートビート設定については、 main server
のみで設定可能であり、 Socket
では設定できませんが、 Socket
main server
のハートビート設定を継承します。
TCPソケットの場合、Swooleのdispatch_mode
が1/3
の場合、 onConnect
イベントとonClose
イベントがブロックされるため、これら2つのイベントのブロックを解除したい場合はdispatch_mode
2/4/5
に設定してください。
' swoole ' => [
//...
' dispatch_mode ' => 2 ,
//...
];
テスト。
TCP: telnet 127.0.0.1 5291
UDP: [Linux] echo "Hello LaravelS" > /dev/udp/127.0.0.1/5292
他のプロトコルの例を登録します。
' 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
必要があります。つまり、 websocket.enable
をtrue
に設定します。 ' sockets ' => [
[
' host ' => ' 0.0.0.0 ' ,
' port ' => 5294 ,
' type ' => SWOOLE_SOCK_TCP ,
' settings ' => [
' open_http_protocol ' => true ,
' open_websocket_protocol ' => true ,
],
' handler ' => App Sockets TestWebSocket::class,
],
],
スウールコルーチン
警告: コルーチン内のコード実行の順序が間違っています。リクエストレベルのデータはコルーチンIDで分離する必要があります。ただし、Laravel/Lumenにはシングルトン属性や静的属性が多く、異なるリクエスト間のデータは相互に影響を与えるため、 Unsafe
はありません。たとえば、データベース接続はシングルトンであり、同じデータベース接続は同じ PDO リソースを共有します。これは、同期ブロッキング モードでは問題ありませんが、非同期コルーチン モードでは機能しません。各クエリは異なる接続を作成し、異なる接続の IO 状態を維持する必要があり、これには接続プールが必要です。
コルーチンを有効にしDO NOT
。コルーチンを使用できるのはカスタム プロセスのみです。
開発者が監視、レポート、またはその他の特別なタスクのための特別な作業プロセスを作成できるようにサポートします。 addProcessを参照してください。
Process クラスを作成し、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
}
}
テストプロセスを登録します。
// 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
],
],
注: callback() は終了できません。終了すると、Manager プロセスはプロセスを再作成します。
例: カスタム プロセスにデータを書き込みます。
// 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
起動時にApollo
設定をプルし、.env
ファイルに書き込みます。同時に、LaravelS
カスタムプロセスapollo
開始して構成を監視し、構成が変更されたときに自動的にreload
。
Apollo を有効にする: --enable-apollo
および Apollo パラメータを起動パラメータに追加します。
php bin/laravels start --enable-apollo --apollo-server=http://127.0.0.1:8080 --apollo-app-id=LARAVEL-S-TEST
ホットアップデートをサポートします(オプション)。
// 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 (),
使用可能なパラメータのリスト。
パラメータ | 説明 | デフォルト | デモ |
---|---|---|---|
アポロサーバー | Apollo サーバーの URL | - | --apollo-server=http://127.0.0.1:8080 |
アポロアプリID | アポロアプリID | - | --apollo-app-id=LARAVEL-S-TEST |
アポロ名前空間 | APP が属する名前空間、複数の指定をサポート | 応用 | --apollo-namespaces=アプリケーション --apollo-namespaces=env |
アポロクラスター | APPが属するクラスター | デフォルト | --apollo-cluster=デフォルト |
アポロクライアントIP | 現在のインスタンスの IP。グレースケール パブリッシュにも使用できます | ローカルイントラネットIP | --apollo-client-ip=10.2.1.83 |
アポロプルタイムアウト | 設定をプルするときのタイムアウト時間(秒) | 5 | --apollo-pull-timeout=5 |
アポロバックアップ-古い環境 | 設定ファイル.env を更新するときに古い設定ファイルをバックアップするかどうか | 間違い | --apollo-backup-old-env |
Prometheus の監視とアラームをサポートし、Grafana は監視メトリクスを視覚的に表示します。 PrometheusとGrafanaの環境構築についてはDocker Composeを参照してください。
拡張機能 APCu >= 5.0.0 が必要です。 pecl install apcu
でインストールしてください。
構成ファイルprometheus.php
プロジェクトのconfig
ディレクトリにコピーします。必要に応じて構成を変更します。
# Execute commands in the project root directory
cp vendor/hhxsv5/laravel-s/config/prometheus.php config/
プロジェクトがLumen
の場合は、構成$app->configure('prometheus');
bootstrap/app.php
内。
global
ミドルウェアを構成します: Hhxsv5LaravelSComponentsPrometheusRequestMiddleware::class
。リクエスト時間の消費をできるだけ正確にカウントするには、 RequestMiddleware
first
グローバル ミドルウェアにする必要があり、他のミドルウェアの前に配置する必要があります。
ServiceProvider を登録します: Hhxsv5LaravelSComponentsPrometheusServiceProvider::class
。
Swoole Worker/Task/Timer プロセスのメトリクスを定期的に収集するように、 config/laravels.php
で CollectorProcess を構成します。
' processes ' => Hhxsv5 LaravelS Components Prometheus CollectorProcess:: getDefinition (),
メトリクスを出力するルートを作成します。
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 ]);
});
Prometheus の構成を完了し、起動します。
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
Grafana を起動し、パネル json をインポートします。
サポートされているイベント:
イベント | インタフェース | いつ起こったのか |
---|---|---|
サーバースタート | Hhxsv5LaravelSSwooleEventsServerStartInterface | マスター プロセスの開始時に発生します。 this event should not handle complex business logic, and can only do some simple work of initialization 。 |
サーバー停止 | Hhxsv5LaravelSSwooleEventsServerStopInterface | サーバーが正常に終了したときに発生します。 CANNOT use async or coroutine related APIs in this event 。 |
ワーカースタート | Hhxsv5LaravelSSwooleEventsWorkerStartInterface | ワーカー/タスクプロセスが開始され、Laravel の初期化が完了した後に発生します。 |
ワーカーストップ | Hhxsv5LaravelSSwooleEventsWorkerStopInterface | ワーカー/タスクプロセスが正常に終了した後に発生します |
ワーカーエラー | Hhxsv5LaravelSSwooleEventsWorkerErrorInterface | ワーカー/タスクのプロセスで例外または致命的なエラーが発生したときに発生します |
1.対応するインターフェースを実装するイベントクラスを作成します。
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.設定。
// Edit `config/laravels.php`
' event_handlers ' => [
' ServerStart ' => [ App Events ServerStartEvent::class], // Trigger events in array order
' WorkerStart ' => [ App Events WorkerStartEvent::class],
],
関数の計算。
bootstrap/app.php
修正し、格納ディレクトリを設定します。プロジェクト ディレクトリは読み取り専用であるため、 /tmp
ディレクトリは読み取りと書き込みのみが可能です。
$ app -> useStoragePath ( env ( ' APP_STORAGE_PATH ' , ' /tmp/storage ' ));
2.シェルスクリプトlaravels_bootstrap
を作成し、 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. 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
FPM モードでは、シングルトン インスタンスはリクエストごとにインスタンス化され、リサイクルされます (リクエストの開始 => インスタンスのインスタンス化 => リクエストの終了 => インスタンスのリサイクル)。
Swoole Server では、すべてのシングルトン インスタンスはメモリに保持され、FPM とはライフタイムが異なります。リクエスト開始 => インスタンスのインスタンス化 => リクエスト終了 => シングルトン インスタンスはリサイクルされません。そのため、開発者はリクエストごとにシングルトン インスタンスのステータスを維持する必要があります。
一般的な解決策:
シングルトン オブジェクトの状態をクリーンアップするXxxCleaner
クラスを作成します。このクラスはインターフェースHhxsv5LaravelSIlluminateCleanersCleanerInterface
を実装し、これをlaravels.php
のcleaners
に登録します。
Middleware
によるシングルトン インスタンスのステータスReset
。
ServiceProvider
を再登録し、ファイルlaravels.php
のregister_providers
にXxxServiceProvider
を追加します。そのため、リクエストごとにシングルトンインスタンスを再初期化する必要があります。
構成クリーナー。
既知の問題: 既知の問題と解決策のパッケージ。
ロギング;コンソールに出力したい場合は、 stderr
、 Log::channel('stderr')->debug('debug message') を使用できます。
Laravel Dump Server (Laravel 5.7 はデフォルトで統合されています)。
IlluminateHttpRequest
オブジェクトによる読み取りリクエスト、$_ENV は読み取り可能、$_SERVER は部分的に読み取り可能、$_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 ();
//...
}
echo/vardump()/print_r() と互換性のあるIlluminateHttpResponse
オブジェクトで応答します。関数 dd()/exit()/die()/header()/setcookie()/http_response_code() はCANNOT USE
。
public function json ()
{
return response ()-> json ([ ' time ' => time ()])-> header ( ' header1 ' , ' value1 ' )-> withCookie ( ' c1 ' , ' v1 ' );
}
Singleton connection
メモリに常駐します。パフォーマンスを向上させるためにpersistent connection
オンにすることをお勧めします。
immediately
自動的に再接続されwill
。 // 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 ,
],
],
],
immediately
自動的に再接続won't
、接続の切断に関する例外がスローされ、次回に再接続されます。 Redisを操作する前に毎回SELECT DB
正しく行われていることを確認する必要があります。 // 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
],
],
グローバル変数の使用は避けてください。必要に応じて、手動でクリーニングまたはリセットしてください。
要素をstatic
/ global
変数に無限に追加すると、OOM (メモリ不足) が発生します。
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 ' );
}
メモリリークの検出方法
config/laravels.php
を変更します: worker_num=1, max_request=1000000
。テスト後に忘れずに元に戻してください。
Worker
プロセスのメモリ変更を監視するには、 route middleware
使用せずにルーティング/debug-memory-leak
を追加します。
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 ;
});
LaravelS
起動し、 diff_mem
ゼロ以下になるまで/debug-memory-leak
リクエストします。 diff_mem
が常に 0 より大きい場合は、 Global Middleware
またはLaravel Framework
でメモリ リークが発生している可能性があることを意味します。
Step 3
を完了した後、ビジネス ルートと/debug-memory-leak
alternately
リクエストします (ビジネス ルートに対して大量のリクエストを行うには、 ab
/ wrk
使用することをお勧めします)。メモリの初期増加は正常です。ビジネス ルートに対する多数のリクエストの後、 diff_mem
が常に 0 より大きく、 curr_mem
増加し続ける場合、メモリ リークが発生する可能性が高くなります。 curr_mem
が常に一定の範囲内で変化し、増加し続けない場合は、メモリ リークが発生する可能性は低くなります。
それでも解決できない場合は、max_request が最後の保証です。
Linuxカーネルパラメータの調整
圧力試験
ペイパル
BTC
ギティ
マサチューセッツ工科大学