LaravelS:通过 Swoole 来加速 Laravel/Lumen

LaravelS - 站在巨人的肩膀上

通过Swoole来加速 Laravel/Lumen,其中的S代表Swoole,速度,高性能。

特性

  • 高性能的Swoole

  • 内置Http服务器

  • 常驻内存

  • 平滑重启

  • 同时支持Laravel与Lumen,兼容主流版本

  • 简单,开箱即用

要求

依赖 说明
PHP >= 5.5.9
Swoole >= 1.7.14 推荐最新的稳定版 从2.0.12开始不再支持PHP5
Laravel/Lumen >= 5.1
Gzip[可选的] zlib, 检查本机libz是否可用ldconfig -p|grep libz

如果对你有帮助,Star Me LaravelS

安装

1.通过Composer安装(packagist)

# 在你的Laravel/Lumen项目的根目录下执行
composer require "hhxsv5/laravel-s:~1.0" -vvv

2.添加service provider

  • Laravel: 修改文件config/app.php

    'providers' => [
    //...
    Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class,
    ],
  • Lumen: 修改文件bootstrap/app.php
    $app->register(Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class);

3.发布配置文件

php artisan laravels publish

特别情况: 你不需要手动加载配置laravels.php,LaravelS底层已自动加载。

// 不必手动加载,但加载了也不会有问题
$app->configure('laravels');

4.修改配置config/laravels.php:监听的IP、端口等,请参考配置项

运行

php artisan laravels {start|stop|restart|reload|publish}

命令 说明
start 启动LaravelS
stop 停止LaravelS
restart 重启LaravelS
reload 平滑重启所有worker进程,这些worker进程内包含你的业务代码和框架(Laravel/Lumen)代码,不会重启master/manger进程
publish 发布配置文件到你的项目中config/laravels.php

与Nginx配合使用

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处理静态资源,LaravelS处理动态资源。
    location / {
        try_files $uri @laravels;
    }

    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 Host $host;
        proxy_pass http://laravels;
    }
}

监听事件

通常,你可以在这些事件中重置或销毁一些全局或静态的变量,也可以修改当前的请求和响应。

  • laravels.received_requestswoole_http_request转成Illuminate\Http\Request后,在Laravel内核处理请求前。
// 修改`app/Providers/EventServiceProvider.php`, 添加下面监听代码到boot方法中
// 如果变量$exents不存在,你也可以调用\Event::listen()。
$events->listen('laravels.received_request', function (\Illuminate\Http\Request $req) {
    $req->query->set('get_key', 'hhxsv5');// 修改querystring
    $req->request->set('post_key', 'hhxsv5'); // 修改post body
});
  • laravels.generated_response 在Laravel内核处理完请求后,将Illuminate\Http\Response转成swoole_http_response之前(下一步将响应给客户端)。
$events->listen('laravels.generated_response', function (\Illuminate\Http\Request $req, \Symfony\Component\HttpFoundation\Response $rsp) {
    $rsp->headers->set('header-key', 'hhxsv5');// 修改header
});

在你的项目中使用swoole_http_server实例

/**
* @var \swoole_http_server
*/
$swoole = app('swoole');// Singleton
var_dump($swoole->stats());

注意事项

  • 只能通过Illuminate\Http\Request对象来获取请求信息,不能使用超全局变量,像$GLOBALS,$_SERVER,$_GET,$_POST,$_FILES,$_COOKIE,$_SESSION,$_REQUEST,$_ENV。
public function form(\Illuminate\Http\Request $request)
{
    $name = $request->input('name');
    $all = $request->all();
    $sessionId = $request->cookie('sessionId');
    $photo = $request->file('photo');
    //...
}
  • 推荐通过返回Illuminate\Http\Response对象来响应请求,兼容echo、vardump()、print_r(),不能使用函数像exit(),die(),header(),setcookie(),http_response_code()。
public function json()
{
    return response()->json(['time' => time()])->header('header1', 'value1')->withCookie('c1', 'v1');
}
  • 你声明的全局、静态变量必须手动清理掉。

  • 无限追加元素到静态或全局变量中,将导致内存爆满。
// 某类
class Test
{
    public static $array = [];
    public static $string = '';
}

// 某控制器
public function test(Request $req)
{
    // 内存爆满
    Test::$array[] = $req->input('param1');
    Test::$string .= $req->input('param2');
}

简单压测

Mac上Docker环境下两容器,Nginx反向代理到PHP,部署的同一套代码,Mac上ab压测。

1.QPS

  • FPM: file
  • LaravelS: file

2.单次响应时间

  • FPM: file
  • LaravelS: file

待办事项

  1. 针对MySQL/Redis的连接池。

  2. 包装MySQL/Redis/Http的协程客户端。

hhxsv5