Английские документы | 中文文档
LaravelS — это готовый адаптер между Laravel/Lumen и Swoole.
Watch
этот репозиторий, чтобы получать последние обновления.Встроенный сервер Http/WebSocket.
Многопортовый смешанный протокол
Пользовательский процесс
Резидент памяти
Асинхронное прослушивание событий
Асинхронная очередь задач
Миллисекундное задание cron
Общие компоненты
Грациозно перезагрузите
Автоматическая перезагрузка после изменения кода
Поддержка Laravel/Lumen, хорошая совместимость.
Простой и готовый к использованию
Какой веб-фреймворк самый быстрый?
Тесты платформы TechEmpower
Зависимость | Требование |
---|---|
PHP | >=8.2 Recommend 8.2 |
Свул | >=5.0 Recommend 5.1.1 |
Ларавел/Люмен | >=10 Recommend 10 |
1. Требуется пакет через Composer (пакетник).
# 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.Зарегистрируйте поставщика услуг (выберите одного из двух).
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
4. Измените config/laravels.php
: Listen_ip, Listen_port, см. Настройки.
5. Настройка производительности
Настройте параметры ядра
Количество воркеров: LaravelS использует режим Synchronous IO
Swoole: чем больше параметр worker_num
, тем выше производительность параллелизма, но это приведет к большему использованию памяти и накладным расходам на переключение процессов. Если один запрос занимает 100 мс, то для обеспечения параллелизма 1000QPS необходимо настроить как минимум 100 рабочих процессов. Метод расчета: worker_num = 1000QPS/(1s/1ms) = 100, поэтому для расчета лучшего worker_num
необходимы дополнительные испытания под давлением.
Количество рабочих
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 до завершения запуска. |
перезагрузить | Перезагрузите все процессы Task/Worker/Timer, которые содержат ваши бизнес-коды, и запустите метод onReload пользовательского процесса. НЕ МОЖЕТ перезагрузить процессы Master/Manger. После изменения config/laravels.php вам нужно only вызвать restart , чтобы перезапустить |
информация | Отображение информации о версии компонента |
помощь | Отображение справочной информации |
start
и restart
.Вариант | Описание |
---|---|
-d|--демонизировать | Запускаться как демон, эта опция переопределит настройку swoole.daemonize в laravels.php |
-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 | Файл конфигурации runtime LaravelS |
хранилище/laravels.pid | PID-файл главного процесса |
хранилище/laravels-timer-process.pid | PID-файл процесса таймера |
хранилище/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 Sever такой же, как и у 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. Также вы можете использовать другие службы глобального хранения, такие как 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.Push данных в контроллере
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
to 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
});
Эта функция зависит от
AsyncTask
Swoole
, вам необходимо сначала установитьswoole.task_worker_num
вconfig/laravels.php
. На производительность асинхронной обработки событий влияет количество процессов задач 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
Эта функция зависит от
AsyncTask
Swoole
, вам необходимо сначала установитьswoole.task_worker_num
вconfig/laravels.php
. На производительность обработки задач влияет количество процессов задач 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
Оболочка cron основана на миллисекундном таймере Swoole, заменяет
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.Примечание: при построении кластера серверов будет запущено несколько таймеров, поэтому вам необходимо убедиться, что запускается только один таймер, чтобы избежать выполнения повторяющихся задач.
4.LaravelS v3.4.0
начинает поддерживать процесс горячего перезапуска [Reload] Timer
. После того, как LaravelS получает сигнал SIGUSR1
, он ждет max_wait_time
(по умолчанию 5) секунд, чтобы завершить процесс, затем процесс Manager
снова запускает процесс Timer
.
5. Если вам нужно использовать только запланированные задачи minute-level
, рекомендуется включить Hhxsv5LaravelSIlluminateLaravelScheduleJob
вместо Linux Crontab, чтобы вы могли следовать привычкам кодирования при планировании задач 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-tools.
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, мы добавили функцию multi-port mixed protocol
Swoole в LaravelS и назвали ее Socket
. Теперь вы можете легко создавать TCP/UDP
-приложения поверх Laravel.
Создайте класс обработчика 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
, даже такие компоненты Laravel, как DB, Eloquent и так далее. В то же время вы можете получить доступ к объекту SwooleServerPort
напрямую с помощью свойства-члена swoolePort
.
public function onReceive ( Server $ server , $ fd , $ reactorId , $ data )
{
$ port = $ this -> swoolePort ; // Get the `SwooleServerPort` object
}
namespace App Http Controllers ;
class TestController extends Controller
{
public function test ()
{
/**@var SwooleHttpServer|SwooleWebSocketServer $swoole */
$ swoole = app ( ' swoole ' );
// $swoole->ports: Traverse all Port objects, https://www.swoole.co.uk/docs/modules/swoole-server/multiple-ports
$ port = $ swoole -> ports [ 0 ]; // Get the `SwooleServerPort` object, $port[0] is the port of the main server
foreach ( $ port -> connections as $ fd ) { // Traverse all connections
// $swoole->send($fd, 'Send tcp message');
// if($swoole->isEstablished($fd)) {
// $swoole->push($fd, 'Send websocket message');
// }
}
}
}
Регистрация сокетов.
// 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-сокета события onConnect
и onClose
будут заблокированы, если для Swoole dispatch_mode
установлено значение 1/3
, поэтому, если вы хотите разблокировать эти два события, установите для 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,
],
],
Сопрограмма Swoole
Внимание: порядок выполнения кода в сопрограмме нарушен. Данные уровня запроса должны быть изолированы по идентификатору сопрограммы. Однако в Laravel/Lumen много одноэлементных и статических атрибутов, данные между разными запросами будут влиять друг на друга, это Unsafe
. Например, соединение с базой данных является одноэлементным, одно и то же соединение с базой данных использует один и тот же ресурс PDO. Это нормально в режиме синхронной блокировки, но не работает в режиме асинхронной сопрограммы. Каждый запрос должен создавать разные соединения и поддерживать состояние ввода-вывода разных соединений, для чего требуется пул соединений.
DO NOT
ВКЛЮЧАЙТЕ сопрограмму, ее может использовать только пользовательский процесс.
Помогите разработчикам создать специальные рабочие процессы для мониторинга, отчетности или других специальных задач. См. AddProcess.
Создайте класс Proccess, реализующий 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
],
],
Примечание. Функция обратного вызова() не может завершиться. В случае выхода процесс 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 (),
Список доступных параметров.
Параметр | Описание | По умолчанию | Демо |
---|---|---|---|
Аполлон-сервер | URL-адрес сервера Apollo | - | --apollo-server=http://127.0.0.1:8080 |
Аполлон-приложение-идентификатор | Идентификатор приложения Apollo | - | --apollo-app-id=LARAVEL-S-TEST |
пространства имен Аполлона | Пространство имен, к которому принадлежит приложение, поддерживает указание нескольких | приложение | --apollo-namespaces=приложение --apollo-namespaces=env |
скопление Аполлона | Кластер, к которому принадлежит приложение | по умолчанию | --apollo-cluster=по умолчанию |
Аполлон-клиент-IP | IP-адрес текущего экземпляра, также можно использовать для публикации в оттенках серого. | IP-адрес локальной интрасети | --apollo-client-ip=10.2.1.83 |
Аполлон-тянуть-тайм-аут | Время ожидания (секунды) при получении конфигурации | 5 | --apollo-pull-timeout=5 |
Аполлон-резервное копирование-старая-окружающая среда | Следует ли создавать резервную копию старого файла конфигурации при обновлении файла конфигурации .env | ЛОЖЬ | --apollo-backup-old-env |
Поддержка мониторинга и сигнализации Prometheus, Grafana для визуального просмотра показателей мониторинга. Пожалуйста, обратитесь к Docker Compose для создания среды Prometheus и Grafana.
Требуется расширение 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
.
Настройте CollectorProcess в config/laravels.php
для регулярного сбора показателей процессов Swoole Worker/Task/Timer.
' 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 ]);
});
Завершите настройку Прометея и запустите его.
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 | Происходит после запуска процесса Worker/Task и завершения инициализации Laravel. |
РабочийСтоп | Hhxsv5LaravelSSwooleEventsWorkerStopInterface | Происходит после нормального завершения процесса Worker/Task. |
Рабочая ошибка | Hhxsv5LaravelSSwooleEventsWorkerErrorInterface | Происходит, когда в процессе Worker/Task возникает исключение или фатальная ошибка. |
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],
],
Функция Вычислить.
1. Измените 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 экземпляры Singleton будут создаваться и перерабатываться в каждом запросе: начало запроса => создание экземпляра => конец запроса => переработанный экземпляр.
На сервере Swoole все одноэлементные экземпляры будут храниться в памяти, время жизни отличается от FPM, начало запроса => создание экземпляра => завершение запроса => не перерабатывать одноэлементный экземпляр. Поэтому разработчику необходимо поддерживать статус экземпляров Singleton в каждом запросе.
Общие решения:
Напишите класс XxxCleaner
для очистки состояния одноэлементного объекта. Этот класс реализует интерфейс Hhxsv5LaravelSIlluminateCleanersCleanerInterface
, а затем регистрирует его в cleaners
laravels.php
.
Reset
статуса одноэлементных экземпляров с помощью Middleware
.
Перерегистрируйте ServiceProvider
, добавьте XxxServiceProvider
в register_providers
файла laravels.php
. Чтобы повторно инициализировать экземпляры Singleton в каждом запросе.
Очистители конфигурации.
Известные проблемы: пакет известных проблем и решений.
Ведение журнала; если вы хотите вывести на консоль, вы можете использовать stderr
, Log::channel('stderr')->debug('отладочное сообщение').
Сервер дампов Laravel (Laravel 5.7 интегрирован по умолчанию).
Запрос на чтение от объекта IlluminateHttpRequest
, $_ENV доступен для чтения, $_SERVER доступен для чтения частично, CANNOT USE
$_GET/$_POST/$_FILES/$_COOKIE/$_REQUEST/$_SESSION/$GLOBALS.
public function form ( Illuminate Http Request $ request )
{
$ name = $ request -> input ( ' name ' );
$ all = $ request -> all ();
$ sessionId = $ request -> cookie ( ' sessionId ' );
$ photo = $ request -> file ( ' photo ' );
// Call getContent() to get the raw POST body, instead of file_get_contents('php://input')
$ rawContent = $ request -> getContent ();
//...
}
Ответить с помощью объекта IlluminateHttpResponse
, совместимого с echo/vardump()/print_r(), CANNOT USE
функции dd()/exit()/die()/header()/setcookie()/http_response_code().
public function json ()
{
return response ()-> json ([ ' time ' => time ()])-> header ( ' header1 ' , ' value1 ' )-> withCookie ( ' c1 ' , ' v1 ' );
}
Singleton connection
будет резидентным в памяти. Для повышения производительности рекомендуется включить persistent connection
.
will
immediately
после отключения. // 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
после отключения и выдаст исключение о потере соединения, подключитесь в следующий раз. Прежде чем каждый раз запускать 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
, не забудьте изменить его обратно после теста;
Добавьте маршрутизацию /debug-memory-leak
без route middleware
чтобы наблюдать за изменениями памяти Worker
процесса;
Route:: get ( ' /debug-memory-leak ' , function () {
global $ previous ;
$ current = memory_get_usage ();
$ stats = [
' prev_mem ' => $ previous ,
' curr_mem ' => $ current ,
' diff_mem ' => $ current - $ previous ,
];
$ previous = $ current ;
return $ stats ;
});
Запустите LaravelS
и запрашивайте /debug-memory-leak
до тех пор, пока diff_mem
не станет меньше или равно нулю; если diff_mem
всегда больше нуля, это означает, что возможна утечка памяти в Global Middleware
или Laravel Framework
;
После выполнения Step 3
alternately
запросите бизнес-маршруты и /debug-memory-leak
(для выполнения большого количества запросов бизнес-маршрутов рекомендуется использовать ab
/ wrk
), первоначальное увеличение памяти является нормальным. Если после большого количества запросов к бизнес-маршрутам diff_mem
всегда больше нуля, а curr_mem
продолжает увеличиваться, существует высокая вероятность утечки памяти; Если curr_mem
всегда изменяется в определенном диапазоне и не продолжает увеличиваться, вероятность утечки памяти мала.
Если вы все еще не можете решить эту проблему, max_request — последняя гарантия.
Настройка параметров ядра Linux
Испытание давлением
PayPal
БТД
Гите
Массачусетский технологический институт