Write the Code. Change the World.

11月 25

Laravel Octane 通过使用功能强大的应用程序服务器(包括 SwooleRoadRunner )为应用程序提供服务,从而增强了应用程序的性能。Octane引导您的应用程序一次,将其保存在内存中,然后以超音速提供请求。

热点

安装条件

  • PHP8+
  • laravel v.8.37+

安装

可以通过Composer软件包管理器安装Octane:

composer require laravel/octane

安装Octane之后,您可以执行 octane:install Artisan 命令,该命令会将Octane的配置文件安装到您的应用程序中:

php artisan octane:install

RoadRunner

RoadRunner 由使用 Go 构建的 RoadRunner 二进制文件提供动力。首次启动基于 RoadRunner 的 Octane 服务器时,Octane 将为您下载并安装 RoadRunner 二进制文件。

RoadRunner Via Laravel Sail

RoadRunner 具体使用可以查看原文。

启动你的服务

可以通过 octane:startArtisan 命令启动 Octane 服务器。默认情况下,此命令将利用 server 应用程序 octane 配置文件的配置选项指定的服务器:

php artisan octane:start
# 设置应用HTTPS.配置
OCTANE_HTTPS=false

# 设置启动服务的容器
OCTANE_SERVER=swoole

# 应用代码热加载
php artisan octane:start --watch

注意 使用该命令之前,应该确保本地安装了Node 服务.您应该在您的project:library中安装Chokidar 文件监视库:

npm install --save-dev chokidar

您可以使用 watch 应用程序的 config/octane.php 配置文件中的配置选项来配置应监视的目录和文件。

指定worker进程数

默认情况下,Octane 将为您的计算机提供的每个 CPU 内核启动一个应用程序请求工作程序。然后,这些工作程序将在进入您的应用程序时用于处理传入的HTTP请求。您可以--workers在调用 octane:star t命令时手动指定要使用该选项的工人数量:

php artisan octane:start --workers=4

如果使用的是 Swoole 应用程序服务器,则还可以指定要启动的“任务工作者”数量:

php artisan octane:start --workers=4 --task-workers=6

指定最大的请求数

php artisan octane:start --max-requests=250

服务重启

您可以使用以下 octane:reload 命令正常重启 Octane 服务器的应用程序工作程序。通常,应在部署后执行此操作,以便将新部署的代码加载到内存中并用于处理后续请求:

php artisan octane:reload

服务停止

您可以使用 octane:stopArtisan 命令停止 Octane 服务器:

php artisan octane:stop

查看服务状态

php artisan octane:status

Octane 依赖注入

由于 Octane 会一次引导您的应用程序并在处理请求时将其保存在内存中,因此在构建应用程序时应注意一些注意事项。例如,您的应用程序服务提供商的registerand boot 方法仅在请求启动程序最初启动时执行一次。在后续请求中,相同的应用程序实例将被重用。
有鉴于此,在将应用程序服务容器或请求注入到任何对象的构造函数中时,应格外小心。这样,该对象可能具有旧版本的容器或后续请求中的请求。
Octane 将自动处理重置请求之间的任何第一方框架状态。但是,Octane 并不总是知道如何重置应用程序创建的全局状态。因此,您应该了解如何以Octane 友好的方式构建应用程序。下面,我们将讨论使用辛烷值时可能引起问题的最常见情况。

容器注入

通常,应避免将应用程序服务容器或 HTTP 请求实例注入其他对象的构造函数中。例如,以下绑定将整个应用程序服务容器注入到作为单例绑定的对象中:

use App\Service;

/**
 * Register any application services.
 *
 * @return void
 */
public function register()
{
    $this->app->singleton(Service::class, function ($app) {
        return new Service($app);
    });
}

在此示例中,如果 Service 在应用程序启动过程中解析了该实例,则该容器将被注入到服务中,并且该 Service 实例将在后续请求中保留该容器。对于您的特定应用程序,这可能不是问题;但是,这可能导致容器意外丢失在引导周期后期或后续请求中添加的绑定。

解决方法是,您可以停止将绑定注册为单例,也可以将容器解析器闭包注入始终解析当前容器实例的服务中:

use App\Service;
use Illuminate\Container\Container;

$this->app->bind(Service::class, function ($app) {
    return new Service($app);
});

$this->app->singleton(Service::class, function () {
    return new Service(fn () => Container::getInstance());
});

全局 app 帮助器和 Container::getInstance() 方法将始终返回应用程序容器的最新版本。

请求注入

通常,应避免将应用程序服务容器或HTTP请求实例注入其他对象的构造函数中。例如,以下绑定将整个请求实例注入到作为单例绑定的对象中:

use App\Service;

/**
 * Register any application services.
 *
 * @return void
 */
public function register()
{
    $this->app->singleton(Service::class, function ($app) {
        return new Service($app['request']);
    });
}

在此示例中,如果Service在应用程序启动过程中解析了实例,则HTTP请求将被注入到服务中,并且该Service实例将在后续请求中保留相同的请求。因此,所有标头,输入和查询字符串数据以及所有其他请求数据都将不正确。

解决方法是,您可以停止将绑定注册为单例,或者可以将请求解析程序闭包注入始终解析当前请求实例的服务中。或者,最推荐的方法只是在运行时将对象需要的特定请求信息传递给对象的方法之一:

use App\Service;

$this->app->bind(Service::class, function ($app) {
    return new Service($app['request']);
});

$this->app->singleton(Service::class, function ($app) {
    return new Service(fn () => $app['request']);
});

// Or...

$service->method($request->input('name'));

全局 request 帮助程序将始终返回应用程序当前正在处理的请求,因此可以在您的应用程序中安全使用。

配置文件注入

通常,应避免将配置实例注入其他对象的构造函数中。例如,以下绑定将配置注入到作为单例绑定的对象中:

use App\Service;

/**
 * Register any application services.
 *
 * @return void
 */
public function register()
{
    $this->app->singleton(Service::class, function ($app) {
        return new Service($app->make('config'));
    });
}

在此示例中,如果配置值在两次请求之间更改,则该服务将无法访问新值,因为它取决于原始存储库实例。
解决方法是,您可以停止将绑定注册为单例,或者可以将配置存储库解析器闭包注入到该类中:

use App\Service;
use Illuminate\Container\Container;

$this->app->bind(Service::class, function ($app) {
    return new Service($app->make('config'));
});

$this->app->singleton(Service::class, function () {
    return new Service(fn () => Container::getInstance()->make('config'));
});

全局 config 将始终返回配置的最新版本,因此可以在您的应用程序中安全使用。

管理内存泄漏

请记住,Octane 在两次请求之间将您的应用程序保留在内存中;因此,将数据添加到静态维护的阵列将导致内存泄漏。例如,由于对应用程>序的每个请求将继续向静态$data数组添加数据,因此以下控制器发生内存泄漏:

use App\Service;
use Illuminate\Http\Request;
use Illuminate\Support\Str;

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return void
 */
public function index(Request $request)
{
    Service::$data[] = Str::random(10);

    // ...
}

并发任务

提示该功能需要使用 Swoole

使用 Swoole 时,您可以通过轻量级后台任务同时执行操作。您可以使用 Octane:: tick concurrently 方法完成此操作。您可以将此方法与PHP数组解>构相结合,以检索每个操作的结果:

use App\User;
use App\Server;
use Laravel\Octane\Facades\Octane;

[$users, $servers] = Octane::concurrently([
    fn () => User::all(),
    fn () => Server::all(),
]);

由 Octane 处理的并发任务利用 Swoole 的 “task workers”,并在与传入请求完全不同的过程中执行。可用于处理并发任务的工作者数量由 --task-workers命令上的 octane:start 指令确定:

php artisan octane:start --workers=4 --task-workers=6

定时器 & 时间间隔

  • 提示该功能需要使用Swoole

使用 Swoole 时,您可以注册将在每指定的秒数内执行的 “tick” 操作。您可以通过 tick 方法注册 “ tick” 回调。提供给该tick方法的第一个参数应该是代表股票行情指示器名称的字符串。第二个参数应该是可调用的,它将在指定的时间间隔被调用。
在此示例中,我们将注册一个闭包,每10秒调用一次。通常,tick应在boot应用程序的服务提供者之一的方法内调用该方法:

Octane::tick('simple-ticker', fn () => ray('Ticking...'))
       ->seconds(10);

使用该 immediate 方法,您可以指示 Octane 在 Octane 服务器最初启动时立即调用 tick 回调,此后每隔 N 秒:

Octane::tick('simple-ticker', fn () => ray('Ticking...'))
        ->seconds(10)
        ->immediate();

Octane 缓存

  • 这功能依赖于Swoole

使用 Swoole 时,您可以利用 Octane 缓存驱动程序,该驱动程序提供每秒高达 200 万次操作的读写速度。因此,对于需要从其缓存层实现极高读/写速度的应用程序而言,此缓存驱动程序是一个绝佳选择。
该缓存驱动程序由 Swoole 表提供动力。缓存中存储的所有数据对服务器上的所有工作人员均可用。但是,重新启动服务器后,将刷新缓存的数据:

Cache::store('octane')->put('framework', 'Laravel', 30);

缓存间隔

除了 Laravel 缓存系统提供的典型方法外,Octane 缓存驱动程序还具有基于间隔的缓存。这些缓存将按指定的时间间隔自动刷新,并应使用 boot 您的应用程序的服务提供商之一的方法进行注册。例如,以下缓存将每五秒钟刷新一次:

use Illuminate\Support\Str;

Cache::store('octane')->interval('random', function () {
    return Str::random(10);
}, seconds: 5);

进程间共享内存 (table)

高性能共享内存

使用 Swoole 时,您可以定义自己的任意 Swoole 表并与之交互。Swoole 表提供了极高的性能吞吐量,并且服务器上的所有工作人员都可以访问这些表中的数据。但是,重新启动服务器后,其中的数据将丢失。

表应在tables应用程序的octane配置文件的配置数组中定义。已经为您配置了一个示例表,该表最多允许1000行。可以通过在列类型之后指定列大小来配置字符串列的最大大小,如下所示:

'tables' => [
    'example:1000' => [
        'name' => 'string:1000',
        'votes' => 'int',
    ],
],

要访问表,可以使用以下 Octane::table 方法:

use Laravel\Octane\Facades\Octane;

Octane::table('example')->set('uuid', [
    'name' => 'Nuno Maduro',
    'votes' => 1000,
]);

return Octane::table('example')->get('uuid');

通过Swoole table 支持的列类型:string,int,和 float。

参考

文章来源
译文
laravel 9 发布
JWT
还要为性能选择 Lumen 吗
Laravel 清单