scil/laravel-fly

通过使用swoole扩展来加速Laravel。

v0.16.6 2019-12-09 12:45 UTC

README

您想使用php 7.4预加载吗?您想使用PHP协程吗?今天您可以使用Swoole与Laravel一起使用。有了LaravelFly,Laravel将像Django 3.0一样开始具备完全的异步能力。

LaravelFly是一个安全方案,通过预加载和协程,加速新的或旧的Laravel 5.5+项目,同时不会产生数据污染或内存泄漏。并且它使得Tinker可以在线使用(在Laravel响应浏览器请求时使用Tinker)。

感谢LaravelSwoolePsySh

注意:好消息!Laravel现在官方支持Swoole,通过laravel/octane!

简单的AB测试

ab -k -n 1000 -c 10 http://zc.test(单次请求执行了21个SQL语句)

测试环境
  • 环境
    • VirtualBox上的ubuntu 16.04(1 CPU:i7-7700HQ 2.80GHz;内存:2G)
    • php7.2 + opcache + fpm和laravelfly的5个工作进程(phpfpm:pm=static pm.max_children=5)
    • 连接池和协程MySQL
  • 测试日期:2018/10

版本兼容性

  • Laravel 5.5 ~ 6.0
  • Swoole >4.2.13

快速开始

1.pecl install swoole
确保在php cli的配置文件中配置extension=swoole.so,而不是fpm。
建议:pecl install inotify

2.composer require "scil/laravel-fly":"dev-master"

3.php vendor/scil/laravel-fly/bin/fly start
如果您启用了eval(tinker())并看到关于mkdir的错误,您可以使用sudo启动LaravelFly。

现在,您的项目正在飞行并监听端口9501。祝您享受。

Docker-compose

composer require "scil/laravel-fly":"dev-master"

php artisan vendor:publish --tag=fly-server

# 127.0.0.1:8080
# you can edit this docker-compos file and use your own nginx conf
docker-compose -f vendor/scil/laravel-fly-local/docker/docker-compose.yml up -d

文档

配置

命令:启动、重新加载 & 调试

编码规范

LaravelFly相关活动

Laravel运行时使用tinker

开发者

推荐包

  • swlib/saber 基于Swoole\Coroutine\Http\Client的协程HTTP客户端。
    类似浏览器的cookie管理,多请求并发,请求/响应拦截器等。
    为确保安全,请在fly.conf.php中设置const LARAVELFLY_COROUTINE = true;

功能和行为

  • 相同的代码可以在PHP-FPM或LaravelFly上运行。LaravelFly可以安装到现有的项目中,而不会影响nginx/apache服务器,也就是说,您可以同时运行LaravelFly服务器和nginx/apache服务器来运行相同的Laravel项目。nginx配置swoole_fallback_to_phpfpm.conf允许您使用LaravelFlyServer作为主服务器,phpfpm作为备份服务器,当LaravelFlyServer不可用时,将请求传递给它。另一个nginx配置use_swoole_or_fpm_depending_on_clients允许我们通过查询字符串?useserver=<swoole|fpm|...选择swoole或fpm服务器。这对于测试非常棒,例如,可以使用eval(tinker())作为fpm支持项目的在线调试器。Apache?laravel-s有一个与Apache合作的示例。

  • 中等策略:默认情况下,每个第三方服务提供者在服务器工作进程上注册(在第一个请求到达服务器之前),在请求中启动。

  • 默认情况下,所有Laravel官方服务都是协程友好的,包括mysql和redis。您可以在任何请求之前创建一个服务或对象。有两种方法:

    • 让服务或对象在多个请求中存活(只有一个服务实例)。LaravelFly称其为工作服务工作对象协程友好服务/对象
    • 在每个请求中克隆服务或对象(一个请求一个实例)。LaravelFly称其为克隆服务克隆对象。这种方法很简单,但经常出现陈旧引用问题。这种类型被laravel-swoolelaravel-s广泛使用,而LaravelFly很少使用。
  • 额外的速度提升,如连接池、中间件缓存、视图路径缓存。

  • 在/laravel-fly/info检查服务器信息。(此功能处于开发中,更多信息将陆续提供。)

  • 不再支持静态文件,因此请与其他服务器一起使用。配置示例:nginxApache

  • swoole-job,Laravel任务或事件监听器可以被投递到swoole任务进程并立即执行,无需再使用artisan queue:work

  • 在路由动作中使用exit()die()会输出内容到控制台或swoole日志,而不会使服务器崩溃或重新加载。如果您想更改此行为,可以分叉LaravalFly并在LaravelFly\Map\Kernel::handle中捕获\Swoole\ExitException

  • 支持连接池。每个请求中只有一个连接可用。但如果你使用fly()fly2(),你可以使用多个连接。

  • 类似于golangswoole提供的go()的函数fly()fly2(),加上Laravel服务可以在fly()fly2()中使用而不需要闭包。《fly2()`具有有限的改变当前请求中服务的能力,例如为当前请求注册新的事件处理器。《fly2()`不建议使用。

在请求中启动的协程,在请求结束时仍然可以存活。以下路由的效果是什么?
它响应“coroutine1; outer1; coroutine2; outer2; outer3”,
但它记录日志“coroutine1; outer1; coroutine2; outer2; outer3; coroutine2.end; coroutine1.end”

// ensure ` const LARAVELFLY_COROUTINE = true;` in fly.conf.php

Route::get('/fly', function () {

    $a = [];
    
    fly(function () use (&$a) {
    
        $a[] = 'coroutine1';
        \co::sleep(2);
        $a[] = 'coroutine1.end';
        \Log::info(implode('; ', $a));
        
        // Eloquent can be used even if current request has ended.
        // $user = new User();
        // $user->name = implode('; ',$a);
        // $user->save();
        
    });

    $a[] = 'outer1';
    

    // go() can use laravel service  with closure
    $log = app('log');
    go(function () use (&$a, $log) {
        $a[] = 'coroutine2';
        \co::sleep(1.2);
        $a[] = 'coroutine2.end';
    });

    $a[] = 'outer2';

    \co::sleep(1);

    $a[] = 'outer3';

    return implode(';', $a);

});

混合swoole和laravel的类似项目

LaravalFly的主要区别特征是对Laravel的重构,就像Django 3.0所做的那样。

1. laravel-swoole

它也是一个安全的解决方案。它支持Lumen和WebSocket。它的文档很棒,也对LaravelFly很有用。

主要区别在于,在laravel-swoole中,用户的代码将由从SwooleTW\Http\Server\Application::$application克隆的新app处理,laravel-swoole更新相关容器绑定到新应用。然而,在LaravelFly中,沙箱不是一个新的应用,而是唯一应用程序容器中的$corDict项。
在LaravelFly中,大多数其他对象如appevent等,默认情况下在工作者进程中始终保持一个对象,不使用clone。LaravelFly使得大多数Laravel对象能够自我保护。这关乎高内聚与低耦合,粒度达到应用程序容器或服务/对象的级别。对于laravel-swoole的用户来说,处理在所有请求之前需要启动的多个包和对象之间的关系是一个巨大的挑战。阅读陈旧引用

LaravelFly中非克隆对象的另一个好处是允许进行一些改进,例如事件监听器缓存、路由中间件缓存。

2. laravel-s

许多优秀功能!

关于数据污染?与laravel-swoole相同的技巧和问题。并且都不支持协程跳跃(从一个请求跳转到另一个请求)。

待改进事项

  • 预包含。服务器配置 'pre_include' 和 'pre_files'。
  • 服务器配置 'early_laravel'
  • LaravelFly应用程序配置缓存。位于bootstrap/cache的laravelfly_ps_map.php或laravelfly_ps_simple.php
  • 日志缓存。服务器选项 'log_cache'。
  • 使用swoole_event_add监控维护模式。无需在每个请求中检查文件storage/framework/down。
  • 内核中间件对象缓存。Kernel::getParsedKernelMiddlewares,只有当LARAVELFLY_SERVICES['kernel']为true时。
  • 路由中间件缓存。Router::gatherRouteMiddleware中的$cacheByRoute,只有当所有路由中间件都在工作者中注册时才有效。
  • 路由中间件对象缓存。config('laravelfly.singleton_route_middlewares')和Router::gatherRouteMiddleware中的$cacheForObj,避免重复创建实例。
  • 终止中间件对象缓存。
  • 事件监听器缓存。LaravelFly\Map\IlluminateBase\Dispatcher中的$listenersStalbe
  • 视图编译路径缓存。LARAVELFLY_SERVICES['view.finder']或应用程序配置'view_compile_1'
  • MySQL协程。弃用旧代码,使用laravel-s。
  • 数据库连接池和Redis连接池。在fly()fly2()中,要使用的连接将从池中获取,而不是从请求协程继承相同的连接。代码:ConnectionsTrait.php中的$this->connections[$childId] = [];
  • Swoole Redis驱动程序
  • Swoole Redis驱动程序:如何使用errMsg errCode
  • 使用hyperf/database替换官方版本?
  • 使用swlib/swpdo替换SwoolePDO?
  • HasRelationships的缓存。禁用和实验性,尚未准备就绪
  • RouteDependencyResolverTrait的缓存
  • 在swoole请求/响应和Laravel Request/Response之间转换
  • 安全:auth,移除一些属性?
  • 使用:https://github.com/louislivi/smproxy
  • 使用:https://github.com/kcloze/swoole-jobshttps://github.com/osgochina/Donkey

其他待办事项

  • 添加事件
  • 监控代码更改和热重载
  • 提供服务器信息。默认URL是:/laravel-fly/info
  • 函数fly()
  • 在任务进程中执行作业。相关:vendor\scil\laravel-fly-files-local\src\Foundation\Bus\
  • 在任务进程中执行事件监听器。相关:LaravelFly\Map\IlluminateBase\Dispatcher和vendor\scil\laravel-fly-files\src\Foundation\Support\Providers\EventServiceProvider.php
  • 在Common.php中使用$this->output而不是echo()
  • 在任务进程中启动所有服务提供者
  • 当其版本3准备好时,为laravel-fly/info尝试使用ocramius/generated-hydrator(它将需要nikic/php-parser v4,这是其他人需要的)// 或Zend\Hydrator\Reflection?
  • 添加关于auth SessionGuard的测试:Illuminate/Auth/SessionGuard.php,使用uses Request::createFromGlobals
  • 添加关于上传文件的测试,相关symfony/http-foundation文件:File/UploadedFile.php和FileBag.php(fixPhpFilesArray)
  • WebSocket
  • 发送文件
  • travis,静态分析工具如phan、phpstan或https://github.com/exakat/php-static-analysis-tools
  • 缓存飞