2021年5月24日13:51:59
官方文档:https://laravel.com/docs/8.x/octane
Laravel Octane
- 介绍
- 安装
- 服务器先决条件
- RoadRunner
- Swoole
- 为您的应用服务
- 通过 HTTPS 为您的应用程序提供服务
- 通过 Nginx 为您的应用程序提供服务
- 监视文件更改
- 指定工人数量
- 指定最大请求计数
- 重新加载工人
- 停止服务器
- 依赖注入和Octane
- 容器注入
- 请求注入
- 配置库注入
- 管理内存泄漏
- 并发任务
- Ticks & Intervals
- Octane 缓存
- 表
介绍
Laravel Octane 通过使用高性能应用服务器(包括Swoole和RoadRunner )为您的应用程序提供服务来增强应用程序的性能。Octane 启动您的应用程序一次,将其保存在内存中,然后以超音速向其发送请求。
安装
Octane 可以通过 Composer 包管理器安装:
composer require laravel/octane
安装 Octane 后,您可以执行octane:install
Artisan 命令,这会将 Octane 的配置文件安装到您的应用程序中:
php artisan octane:install
服务器先决条件
Laravel Octane 需要PHP 8.0+。
RoadRunner
RoadRunner由 RoadRunner 二进制文件提供支持,该二进制文件是使用 Go 构建的。当您第一次启动基于 RoadRunner 的 Octane 服务器时,Octane 会为您下载并安装 RoadRunner 二进制文件。
RoadRunner 通过 Laravel Sail
如果你打算使用Laravel Sail开发你的应用程序,你应该运行以下命令来安装 Octane 和 RoadRunner:
./vendor/bin/sail up
./vendor/bin/sail composer require laravel/octane spiral/roadrunner
接下来,您应该启动一个 Sail shell 并使用rr
可执行文件来检索 RoadRunner 二进制文件的最新基于 Linux 的构建:
./vendor/bin/sail shell
# Within the Sail shell...
./vendor/bin/rr get-binary
安装 RoadRunner 二进制文件后,您可以退出 Sail shell 会话。您现在需要调整supervisor.conf
Sail 使用的文件以保持应用程序运行。首先,执行sail:publish
Artisan 命令:
./vendor/bin/sail artisan sail:publish
接下来,更新command
您的应用程序docker/supervisord.conf
文件的指令,以便 Sail 使用 Octane 而不是 PHP 开发服务器为您的应用程序提供服务:
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=roadrunner --host=0.0.0.0 --rpc-port=6001 --port=8000
最后,确保rr
二进制文件是可执行的并构建您的 Sail 镜像:
chmod +x ./rr
./vendor/bin/sail build --no-cache
Swoole
如果你打算使用 Swoole 应用服务器来为你的 Laravel Octane 应用提供服务,你必须安装 Swoole PHP 扩展。通常,这可以通过 PECL 完成:
pecl install swoole
通过 Laravel Sail Swoole
在通过 Sail 提供 Octane 应用程序之前,请确保您拥有最新版本的 Laravel Sail 并
./vendor/bin/sail build --no-cache
在应用程序的根目录中执行。
或者,您可以使用Laravel Sail开发基于 Swoole 的 Octane 应用程序,Laravel 基于Docker 的官方开发环境。Laravel Sail 默认包含 Swoole 扩展。但是,您仍然需要调整supervisor.conf
Sail 使用的文件以保持应用程序运行。首先,执行sail:publish
Artisan 命令:
./vendor/bin/sail artisan sail:publish
接下来,更新command
您的应用程序docker/supervisord.conf
文件的指令,以便 Sail 使用 Octane 而不是 PHP 开发服务器为您的应用程序提供服务:
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=swoole --host=0.0.0.0 --port=8000
最后,构建您的 Sail 镜像:
./vendor/bin/sail build --no-cache
为您的应用服务
Octane 服务器可以通过octane:start
Artisan 命令启动。默认情况下,此命令将使用由server
应用程序octane
配置文件的配置选项指定的服务器:
php artisan octane:start
默认情况下,Octane 将在端口 8000 上启动服务器,因此您可以通过http://localhost:8000
.
通过 HTTPS 为您的应用程序提供服务
默认情况下,通过 Octane 运行的应用程序生成前缀为http://
. OCTANE_HTTPS
在您的应用程序的config/octane.php
配置文件中使用的环境变量可以在true
通过 HTTPS 为您的应用程序提供服务时设置。当此配置值设置为 时true
,Octane 将指示 Laravel 为所有生成的链接添加前缀https://
:
'https' => env('OCTANE_HTTPS', false),
通过 Nginx 为您的应用程序提供服务
如果您还没有准备好管理自己的服务器配置,或者不习惯配置运行强大的 Laravel Octane 应用程序所需的所有各种服务,请查看Laravel Forge。
在生产环境中,您应该在传统 Web 服务器(例如 Nginx 或 Apache)后面为 Octane 应用程序提供服务。这样做将允许 Web 服务器为您的静态资产(例如图像和样式表)提供服务,并管理您的 SSL 证书终止。
在下面的 Nginx 配置示例文件中,Nginx 将向在端口 8000 上运行的 Octane 服务器提供站点的静态资产和代理请求:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name domain.com;
server_tokens off;
root /home/forge/domain.com/public;
index index.php;
charset utf-8;
location /index.php {
try_files /not_exists @octane;
}
location / {
try_files $uri $uri/ @octane;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/domain.com-error.log error;
error_page 404 /index.php;
location @octane {
set $suffix "";
if ($uri = /index.php) {
set $suffix ?$query_string;
}
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header SERVER_PORT $server_port;
proxy_set_header REMOTE_ADDR $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://127.0.0.1:8000$suffix;
}
}
监视文件更改
由于您的应用程序在 Octane 服务器启动时加载到内存中,因此在您刷新浏览器时不会反映对应用程序文件的任何更改。例如,routes/web.php
在服务器重新启动之前,添加到文件中的路由定义不会被反映。为方便起见,您可以使用该--watch
标志来指示 Octane 在应用程序中的任何文件更改时自动重新启动服务器:
php artisan octane:start --watch
在使用此功能之前,您应该确保Node安装在您的本地开发环境中。此外,您应该在您的 project:library 中安装Chokidar文件监视库:
npm install --save-dev chokidar
您可以使用watch
应用程序config/octane.php
配置文件中的配置选项来配置应该监视的目录和文件。
指定工人数量
默认情况下,Octane 将为您的机器提供的每个 CPU 内核启动一个应用程序请求工作程序。然后,这些工作人员将用于在进入您的应用程序时为传入的 HTTP 请求提供服务。您可以--workers
在调用octane:start
命令时手动指定要开始使用该选项的工人数量:
php artisan octane:start --workers=4
如果您使用的是 Swoole 应用服务器,您还可以指定您希望启动多少个“任务工作者”:
php artisan octane:start --workers=4 --task-workers=6
指定最大请求计数
为了帮助防止杂散内存泄漏,Octane 可以在处理了给定数量的请求后优雅地重新启动工作程序。要指示 Octane 执行此操作,您可以使用以下--max-requests
选项:
php artisan octane:start --max-requests=250
重新加载工人
您可以使用该octane:reload
命令优雅地重新启动 Octane 服务器的应用程序工作线程。通常,这应该在部署后完成,以便将新部署的代码加载到内存中并用于为后续请求提供服务:
php artisan octane:reload
停止服务器
您可以使用octane:stop
Artisan 命令停止 Octane 服务器:
php artisan octane:stop
检查服务器状态
您可以使用octane:status
Artisan 命令检查 Octane 服务器的当前状态:
php artisan octane:status
依赖注入和octane
由于 Octane 引导您的应用程序一次并在处理请求时将其保存在内存中,因此在构建应用程序时您应该考虑一些注意事项。例如,您的应用程序服务提供者的register
和boot
方法只会在请求工作器最初启动时执行一次。在后续请求中,将重用相同的应用程序实例。
有鉴于此,在将应用服务容器或请求注入任何对象的构造函数时应特别小心。通过这样做,该对象可能具有容器的陈旧版本或对后续请求的请求。
Octane 将自动处理在请求之间重置任何第一方框架状态。但是,Octane 并不总是知道如何重置由您的应用程序创建的全局状态。因此,您应该了解如何以一种对 Octane 友好的方式构建您的应用程序。下面,我们将讨论在使用 Octane 时可能导致问题的最常见情况。
容器注入
一般来说,你应该避免将应用服务容器或 HTTP 请求实例注入到其他对象的构造函数中。例如,以下绑定将整个应用程序服务容器注入到绑定为单例的对象中:
use AppService;
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->singleton(Service::class, function ($app) {
return new Service($app);
});
}
在此示例中,如果Service
在应用程序启动过程中解析了实例,则容器将被注入到服务中,并且该容器将Service
在后续请求中由实例持有。对于您的特定应用程序,这可能不是问题;但是,它可能导致容器意外丢失在引导周期后期或由后续请求添加的绑定。
作为一种解决方法,您可以停止将绑定注册为单例,或者您可以将容器解析器闭包注入到始终解析当前容器实例的服务中:
use AppService;
use IlluminateContainerContainer;
$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 AppService;
/**
* 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 AppService;
$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
助手将始终返回应用程序当前正在处理的请求,因此可以安全地在您的应用程序中使用。
IlluminateHttpRequest
在您的控制器方法和路由闭包上键入提示实例是可以接受的。
配置库注入
通常,您应该避免将配置存储库实例注入到其他对象的构造函数中。例如,以下绑定将配置存储库注入到绑定为单例的对象中:
use AppService;
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->singleton(Service::class, function ($app) {
return new Service($app->make('config'));
});
}
在此示例中,如果配置值在请求之间发生更改,则该服务将无法访问新值,因为它取决于原始存储库实例。
作为一种解决方法,您可以停止将绑定注册为单例,或者您可以将配置存储库解析器闭包注入该类:
use AppService;
use IlluminateContainerContainer;
$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 AppService;
use IlluminateHttpRequest;
use IlluminateSupportStr;
/**
* Handle an incoming request.
*
* @param IlluminateHttpRequest $request
* @return void
*/
public function index(Request $request)
{
Service::$data[] = Str::random(10);
// ...
}
在构建您的应用程序时,您应该特别注意避免产生这些类型的内存泄漏。建议您在本地开发期间监控应用程序的内存使用情况,以确保不会将新的内存泄漏引入应用程序。
并发任务
此功能需要Swoole。
使用 Swoole 时,您可以通过轻量级后台任务并发执行操作。您可以使用 Octane 的concurrently
方法完成此操作。您可以将此方法与 PHP 数组解构结合使用,以检索每个操作的结果:
use AppUser;
use AppServer;
use LaravelOctaneFacadesOctane;
[$users, $servers] = Octane::concurrently([
fn () => User::all(),
fn () => Server::all(),
]);
Octane 处理的并发任务利用 Swoole 的“任务工作者”,并在与传入请求完全不同的进程中执行。可用于处理并发任务的工人数量由命令中的--task-workers
指令决定octane:start
:
php artisan octane:start --workers=4 --task-workers=6
Ticks & Intervals
此功能需要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);
Octane 缓存中允许的最大条目数可以在应用程序的
octane
配置文件中定义。
缓存间隔
除了 Laravel 缓存系统提供的典型方法之外,Octane 缓存驱动程序还具有基于间隔的缓存。这些缓存会在指定的时间间隔自动刷新,并且应该在boot
您的应用程序的服务提供者之一的方法中注册。例如,以下缓存将每五秒刷新一次:
use IlluminateSupportStr;
Cache::store('octane')->interval('random', function () {
return Str::random(10);
}, seconds: 5)
表
此功能需要Swoole。
使用 Swoole 时,您可以定义自己的任意Swoole 表并与之交互。Swoole 表提供了极高的性能吞吐量,这些表中的数据可以被服务器上的所有工作人员访问。但是,当服务器重新启动时,其中的数据将丢失。
表应该在tables
应用程序octane
配置文件的配置数组中定义。已经为您配置了一个最多允许 1000 行的示例表。可以通过在列类型后指定列大小来配置字符串列的最大大小,如下所示:
'tables' => [
'example:1000' => [
'name' => 'string:1000',
'votes' => 'int',
],
],
要访问表,您可以使用以下Octane::table
方法:
use LaravelOctaneFacadesOctane;
Octane::table('example')->set('uuid', [
'name' => 'Nuno Maduro',
'votes' => 1000,
]);
return Octane::table('example')->get('uuid');
通过Swoole表格支持的列类型:
string
,int
,和float
。