itxiao6/laravel-s
Composer 安装命令:
composer require itxiao6/laravel-s
包简介
🚀 LaravelS: speed up Laravel/Lumen by Swoole, let's fly.
关键字:
README 文档
README
_ _ _____
| | | |/ ____|
| | __ _ _ __ __ ___ _____| | (___
| | / _` | '__/ _` \ \ / / _ \ |\___ \
| |___| (_| | | | (_| |\ V / __/ |____) |
|______\__,_|_| \__,_| \_/ \___|_|_____/
🚀 Speed up Laravel/Lumen by
Swoole, let's fly.
Features
-
Built-in Http/WebSocket server
-
Memory resident
-
Gracefully reload
-
Automatically reload when code is modified
-
Support Laravel/Lumen both, good compatibility
-
Simple & Out of the box
Requirements
| Dependency | Requirement |
|---|---|
| PHP | >= 5.5.9 |
| Swoole | >= 1.7.19 The Newer The Better No longer support PHP5 since 2.0.12 |
| Laravel/Lumen | >= 5.1 |
| Gzip[optional] | zlib, be used to compress the HTTP response, check by ldconfig -p|grep libz |
| Inotify[optional] | inotify, be used to reload all worker processes when your code is modified, check by php --ri inotify |
Install
1.Require package via Composer(packagist).
# Run in the root path of your Laravel/Lumen project. composer require "hhxsv5/laravel-s:~1.0" -vvv # Make sure that your composer.lock file is under the VCS
2.Register service provider.
Laravel: inconfig/app.phpfile
'providers' => [ //... Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class, ],
Lumen: inbootstrap/app.phpfile
$app->register(Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class);
3.Publish configuration.
Suggest that do publish after upgrade LaravelS every time
php artisan laravels publish
Special for Lumen: you DO NOT need to load this configuration manually in bootstrap/app.php file, LaravelS will load it automatically.
// Unnecessary to call configure() $app->configure('laravels');
4.Change config/laravels.php: listen_ip, listen_port, refer Settings.
Run demo
php artisan laravels {start|stop|restart|reload|publish}
| Command | Description |
|---|---|
start |
Start LaravelS, list the processes by ps -ef|grep laravels |
stop |
Stop LaravelS |
restart |
Restart LaravelS |
reload |
Reload all worker processes(Contain your business & Laravel/Lumen codes), exclude master/manger process |
publish |
Publish configuration file laravels.php into folder config |
Cooperate with Nginx (Recommended)
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 laravels { server 192.168.0.1:5200 weight=5 max_fails=3 fail_timeout=30s; #server 192.168.0.2:5200 weight=3 max_fails=3 fail_timeout=30s; #server 192.168.0.3:5200 backup; } server { listen 80; server_name laravels.com; root /xxxpath/laravel-s-test/public; access_log /yyypath/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_http_version 1.1; # proxy_connect_timeout 60s; # proxy_send_timeout 60s; # proxy_read_timeout 120s; proxy_set_header Connection "keep-alive"; 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://laravels; } }
Cooperate with Apache
LoadModule proxy_module /yyypath/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> ServerName www.laravels.com ServerAdmin hhxsv5@sina.com DocumentRoot /xxxpath/laravel-s-test/public; DirectoryIndex index.html index.htm <Directory "/"> AllowOverride None Require all granted </Directory> LoadModule proxy_module /yyypath/modules/mod_proxy.so LoadModule proxy_module /yyypath/modules/mod_proxy_balancer.so LoadModule proxy_module /yyypath/modules/mod_lbmethod_byrequests.so.so LoadModule proxy_module /yyypath/modules/mod_proxy_http.so.so LoadModule proxy_module /yyypath/modules/mod_slotmem_shm.so LoadModule proxy_module /yyypath/modules/mod_rewrite.so ProxyRequests Off ProxyPreserveHost On <Proxy balancer://laravels> BalancerMember http://192.168.1.1:8011 loadfactor=7 #BalancerMember http://192.168.1.2:8011 loadfactor=3 #BalancerMember http://192.168.1.3:8011 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>
Enable WebSocket server
The Listening address of WebSocket Sever is the same as Http Server.
1.Create WebSocket Handler class, and implement interface WebSocketHandlerInterface.
namespace App\Services; use Hhxsv5\LaravelS\Swoole\WebSocketHandlerInterface; /** * @see https://www.swoole.co.uk/docs/modules/swoole-websocket-server */ class WebSocketService implements WebSocketHandlerInterface { // Declare constructor without parameters public function __construct() { } public function onOpen(\swoole_websocket_server $server, \swoole_http_request $request) { // Laravel has finished its lifetime before triggering onOpen event, so Laravel's Request & Session are available here, Request is readable only, Session is readable & writable both. \Log::info('New WebSocket connection', [$request->fd, request()->all(), session()->getId(), session('xxx'), session(['yyy' => time()])]); $server->push($request->fd, 'Welcome to LaravelS'); // throw new \Exception('an exception');// all exceptions will be ignored, then record them into Swoole log, you need to try/catch them } public function onMessage(\swoole_websocket_server $server, \swoole_websocket_frame $frame) { \Log::info('Received message', [$frame->fd, $frame->data, $frame->opcode, $frame->finish]); $server->push($frame->fd, date('Y-m-d H:i:s')); // throw new \Exception('an exception');// all exceptions will be ignored, then record them into Swoole log, you need to try/catch them } public function onClose(\swoole_websocket_server $server, $fd, $reactorId) { // throw new \Exception('an exception');// all exceptions will be ignored, then record them into Swoole log, you need to try/catch them } }
2.Modify config/laravels.php.
// ... 'websocket' => [ 'enable' => 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.Use swoole_table to bind FD & UserId, optional, Swoole Table Demo. Also you can use the other global storage services, like Redis/Memcached/MySQL, but be careful that FD will be possible conflicting between multiple Swoole Servers.
4.Cooperate with Nginx (Recommended)
Refer WebSocket Proxy
map $http_upgrade $connection_upgrade { default upgrade; '' close; } upstream laravels { server 192.168.0.1:5200 weight=5 max_fails=3 fail_timeout=30s; #server 192.168.0.2:5200 weight=3 max_fails=3 fail_timeout=30s; #server 192.168.0.3:5200 backup; } server { listen 80; server_name laravels.com; root /xxxpath/laravel-s-test/public; access_log /yyypath/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" # Javascript: var ws = new WebSocket("ws://laravels.com/ws"); location =/ws { proxy_http_version 1.1; # proxy_connect_timeout 60s; # proxy_send_timeout 60s; # proxy_read_timeout: Nginx will close the connection if client does not send data to server in 60 seconds; At the same time, this close behavior is also affected by heartbeat setting of Swoole # proxy_read_timeout 60s; 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://laravels; } location @laravels { proxy_http_version 1.1; # proxy_connect_timeout 60s; # proxy_send_timeout 60s; # proxy_read_timeout 60s; 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://laravels; } }
Listen events
System events
Usually, you can reset/destroy some
global/staticvariables, or change the currentRequest/Responseobject.
laravels.received_requestAfter LaravelS parsedswoole_http_requesttoIlluminate\Http\Request, before Laravel's Kernel handles this request.
// 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_responseAfter Laravel's Kernel handled the request, before LaravelS parsesIlluminate\Http\Responsetoswoole_http_response.
// 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 });
Customized asynchronous events
This feature depends on
AsyncTaskofSwoole, your need to setswoole.task_worker_numinconfig/laravels.phpfirstly. The performance of asynchronous event processing is influenced by number of Swoole task process, you need to set task_worker_num appropriately.
1.Create event class.
use Hhxsv5\LaravelS\Swoole\Task\Event; class TestEvent extends Event { private $data; public function __construct($data) { $this->data = $data; } public function getData() { return $this->data; } }
2.Create listener class.
use Hhxsv5\LaravelS\Swoole\Task\Event; use Hhxsv5\LaravelS\Swoole\Task\Listener; class TestListener1 extends Listener { // Declare constructor without parameters public function __construct() { } public function handle(Event $event) { \Log::info(__CLASS__ . ':handle start', [$event->getData()]); sleep(2);// Simulate the slow codes // throw new \Exception('an exception');// all exceptions will be ignored, then record them into Swoole log, you need to try/catch them } }
3.Bind event & listeners.
// Bind event & listeners in file "config/laravels.php", one event => many listeners [ // ... 'events' => [ \App\Tasks\TestEvent::class => [ \App\Tasks\TestListener1::class, //\App\Tasks\TestListener2::class, ], ], // ... ];
4.Fire event.
// Create instance of event and fire it, "fire" is asynchronous. use Hhxsv5\LaravelS\Swoole\Task\Event; $success = Event::fire(new TestEvent('event data')); var_dump($success);// Return true if sucess, otherwise false
Asynchronous task queue
This feature depends on
AsyncTaskofSwoole, your need to setswoole.task_worker_numinconfig/laravels.phpfirstly. The performance of task processing is influenced by number of Swoole task process, you need to set task_worker_num appropriately.
1.Create task class.
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 // throw new \Exception('an exception');// all exceptions will be ignored, then record them into Swoole log, you need to try/catch them $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.Deliver task.
// 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 $ret = Task::deliver($task); var_dump($ret);// Return true if sucess, otherwise false
Millisecond cron job
Wrapper cron job base on Swoole's Millisecond Timer, replace
LinuxCrontab.
1.Create cron job class.
namespace App\Jobs\Timer; use Hhxsv5\LaravelS\Swoole\Timer\CronJob; class TestCronJob extends CronJob { protected $i = 0; // Declare constructor without parameters public function __construct() { } public function interval() { return 1000;// Run every 1000ms } public function isImmediate() { return false;// Whether to trigger `run` immediately after setting up } public function run() { \Log::info(__METHOD__, ['start', $this->i, microtime(true)]); // do something $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 } // throw new \Exception('an exception');// all exceptions will be ignored, then record them into Swoole log, you need to try/catch them } }
2.Bind cron job.
// Bind 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 //\Hhxsv5\LaravelS\Illuminate\LaravelScheduleJob::class, \App\Jobs\Timer\TestCronJob::class, ], ], // ... ];
3.Note: it will launch multiple timers when build the server cluster, so you need to make sure that launch one timer only to avoid running repetitive task.
Get the instance of swoole_server in your project
/** * $swoole is the instance of `swoole_websocket_server` if enable WebSocket server, otherwise `\swoole_http_server` * @var \swoole_http_server|\swoole_websocket_server $swoole */ $swoole = app('swoole'); var_dump($swoole->stats());// Singleton
Use swoole_table
1.Define swoole_table, support multiple.
All defined tables will be created before Swoole starting.
// 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 conficts. 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.Access swoole_table: all table instances will be bound on swoole_server, access by app('swoole')->xxxTable.
// Scene:bind UserId & FD in WebSocket public function onOpen(\swoole_websocket_server $server, \swoole_http_request $request) { // var_dump(app('swoole') === $server);// The same instance $userId = mt_rand(1000, 10000); app('swoole')->wsTable->set('uid:' . $userId, ['value' => $request->fd]);// Bind map uid to fd app('swoole')->wsTable->set('fd:' . $request->fd, ['value' => $userId]);// Bind map fd to uid $server->push($request->fd, 'Welcome to LaravelS'); } public function onMessage(\swoole_websocket_server $server, \swoole_websocket_frame $frame) { foreach (app('swoole')->wsTable as $key => $row) { if (strpos($key, 'uid:') === 0) { $server->push($row['value'], 'Broadcast: ' . date('Y-m-d H:i:s'));// Broadcast } } } public function onClose(\swoole_websocket_server $server, $fd, $reactorId) { $uid = app('swoole')->wsTable->get('fd:' . $fd); if ($uid !== false) { app('swoole')->wsTable->del('uid:' . $uid['value']); // Ubind uid map } app('swoole')->wsTable->del('fd:' . $fd);// Unbind fd map $server->push($fd, 'Goodbye'); }
Multi-port mixed protocol
For more information, please refer to Swoole Server AddListener
To make our main server support more protocols not just Http and WebSocket, we bring the feature multi-port mixed protocol of Swoole in LaravelS and name it Socket. Now, you can build TCP/UDP applications easily on top of Laravel.
- Create socket handler class, and extend
Hhxsv5\LaravelS\Swoole\Socket\{TcpSocket|UdpSocket|Http|WebSocket}.
namespace App\Sockets; use Hhxsv5\LaravelS\Swoole\Socket\TcpSocket; class TestTcpSocket extends TcpSocket { public function onConnect(\swoole_server $server, $fd, $reactorId) { \Log::info('New TCP connection', [$fd]); $server->send($fd, 'Welcome to LaravelS.'); } public function onReceive(\swoole_server $server, $fd, $reactorId, $data) { \Log::info('Received data', [$fd, $data]); $server->send($fd, 'LaravelS: ' . $data); if ($data === "quit\r\n") { $server->send($fd, 'LaravelS: bye' . PHP_EOL); $server->close($fd); } } public function onClose(\swoole_server $server, $fd, $reactorId) { \Log::info('New TCP connection', [$fd]); $server->send($fd, 'Goodbye'); } }
These Socket connections share the same worker processes with your HTTP/WebSocket connections. So it won't be a problem at all if you want to deliver tasks, use swoole_table, even Laravel components such as DB, Eloquent and so on.
At the same time, you can access swoole_server_port object directly by member property swoolePort.
public function onReceive(\swoole_server $server, $fd, $reactorId, $data) { $port = $this->swoolePort; //There you go }
- Register Sockets.
// Edit `config/laravels.php` //... 'sockets' => [ [ 'host' => '127.0.0.1', 'port' => 5291, 'type' => SWOOLE_SOCK_TCP,// Socket type: SWOOLE_SOCK_TCP/SWOOLE_SOCK_UDP 'settings' => [// Swoole settings:https://www.swoole.co.uk/docs/modules/swoole-server-methods#swoole_server-addlistener 'open_eof_check' => true, 'package_eof' => "\r\n", ], 'handler' => \App\Sockets\TestTcpSocket::class, ], ],
For TCP socket, onConnect and onClose events will be blocked when dispatch_mode of Swoole is 1/3, so if you want to unblock these two events please set dispatch_mode to 2/4/5.
'swoole' => [ //... 'dispatch_mode' => 2, //... ];
- Test.
-
TCP:
telnet 127.0.0.1 5291 -
UDP: [Linux]
echo "Hello LaravelS" > /dev/udp/127.0.0.1/5292
- Register example of other protocols.
- UDP
'sockets' => [ [ 'host' => '0.0.0.0', 'port' => 5292, 'type' => SWOOLE_SOCK_UDP, 'settings' => [ 'open_eof_check' => true, 'package_eof' => "\r\n", ], 'handler' => \App\Sockets\TestUdpSocket::class, ], ],
- Http
'sockets' => [ [ 'host' => '0.0.0.0', 'port' => 5293, 'type' => SWOOLE_SOCK_TCP, 'settings' => [ 'open_http_protocol' => true, ], 'handler' => \App\Sockets\TestHttp::class, ], ],
- WebSocket
'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, ], ],
Coroutine MySQL
Support coroutine client for MySQL database.
1.Requirements: Swoole>=4.0, Laravel>=5.1(Lumen will be supported later).
2.Change the driver of MySQL connection to sw-co-mysql in file config/database.php.
'connections' => [ //... 'mysql-test' => [ //'driver' => 'mysql', 'driver' => 'sw-co-mysql', 'host' => env('DB_HOST', 'localhost'), 'port' => env('DB_PORT', 3306), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'strict' => true, ], //... ],
3.Replace Illuminate\Database\DatabaseServiceProvider::class of providers to \Hhxsv5\LaravelS\Illuminate\Database\DatabaseServiceProvider::class in file config/app.php.
'providers' => [ //... //Illuminate\Database\DatabaseServiceProvider::class,// Just annotate this line. \Hhxsv5\LaravelS\Illuminate\Database\DatabaseServiceProvider::class, //... ],
4.Now, you just use QueryBuilder and ORM as usual. (Alpha stage, there should be some bugs, please give us your feedback).
Important notices
-
Singleton Issue-
Under FPM mode, singleton instances will be instantiated and recycled in every request, request start=>instantiate instance=>request end=>recycled instance.
-
Under Swoole Server, All singleton instances will be held in memory, different lifetime from FPM, request start=>instantiate instance=>request end=>do not recycle singleton instance. So need developer to maintain status of singleton instances in ervery request.
-
Common solutions:
-
Resetstatus of singleton instances byMiddleware. -
Re-register
ServiceProvider, addXxxServiceProviderintoregister_providersof filelaravels.php. So that reinitialize singleton instances in ervery request Refer.
-
-
-
Get all info of request from
Illuminate\Http\RequestObject, compatible with $_SERVER/$_ENV/$_GET/$_POST/$_FILES/$_COOKIE/$_REQUEST,CANNOT USE$_SESSION.
public function form(\Illuminate\Http\Request $request) { $name = $request->input('name'); $all = $request->all(); $sessionId = $request->cookie('sessionId'); $photo = $request->file('photo'); $rawContent = $request->getContent(); //... }
- Respond by
Illuminate\Http\ResponseObject, compatible with echo/vardump()/print_r(),CANNOT USEfunctions like header()/setcookie()/http_response_code().
public function json() { return response()->json(['time' => time()])->header('header1', 'value1')->withCookie('c1', 'v1'); }
- The various
singleton connectionswill bememory resident, recommend to enablepersistent connection.
- Database connection, it
willreconnect automaticallyimmediatelyafter disconnect.
// 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, ], ], //... ], //...
- Redis connection, it
won'treconnect automaticallyimmediatelyafter disconnect, and will throw an exception about lost connection, reconnect next time. You need to make sure thatSELECT DBcorrectly before operating Redis every time.
// config/database.php 'redis' => [ 'default' => [ 'host' => env('REDIS_HOST', 'localhost'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 0, 'persistent' => true, // Enable persistent connection ], ], //...
-
global,staticvariables which you declared are need to destroy(reset) manually. -
Infinitely appending element into
static/globalvariable will lead to memory leak.
// Some class class Test { public static $array = []; public static $string = ''; } // Controller public function test(Request $req) { // Memory leak Test::$array[] = $req->input('param1'); Test::$string .= $req->input('param2'); }
Todo list
-
Connection pool for MySQL/Redis.
-
Wrap coroutine clients for MySQL(alpha stage)/Redis/Http.
Alternatives
License
itxiao6/laravel-s 适用场景与选型建议
itxiao6/laravel-s 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 16 次下载、GitHub Stars 达 1, 最近一次更新时间为 2018 年 06 月 15 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「coroutine」 「http server」 「High Performance」 「swoole」 「websocket server」 「async event」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 itxiao6/laravel-s 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 itxiao6/laravel-s 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 itxiao6/laravel-s 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Asynchronous coroutines for PHP 7.
repository php library
A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.
A jQuery augmented PHP library for creating and validating HTML forms
annotations-scan-plugin
http客户端
统计信息
- 总下载量: 16
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 2
- 点击次数: 10
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2018-06-15