メインコンテンツまでスキップ

Laravel Octane

導入

Laravel Octane は、FrankenPHPOpen SwooleSwoole、および RoadRunner を含む高性能なアプリケーションサーバーを使用してアプリケーションのパフォーマンスを向上させます。Octane はアプリケーションを一度起動し、メモリに保持した後、超音速の速度でリクエストを処理します。

インストール

Octane は Composer パッケージマネージャーを使用してインストールできます:

composer require laravel/octane

Octane をインストールした後、octane:install Artisan コマンドを実行すると、Octane の設定ファイルがアプリケーションにインストールされます:

php artisan octane:install

サーバーの前提条件

警告

Laravel Octane は PHP 8.1+ が必要です。

FrankenPHP

FrankenPHP は、Go で書かれた PHP アプリケーションサーバーで、early hints、Brotli、Zstandard 圧縮などのモダンな Web 機能をサポートしています。Octane をインストールし、サーバーとして FrankenPHP を選択すると、Octane は自動的に FrankenPHP バイナリをダウンロードしてインストールします。

Laravel Sail を介した FrankenPHP

Laravel Sail を使用してアプリケーションを開発する場合は、次のコマンドを実行して Octane と FrankenPHP をインストールする必要があります:

./vendor/bin/sail up

./vendor/bin/sail composer require laravel/octane

次に、octane:install Artisan コマンドを使用して FrankenPHP バイナリをインストールする必要があります:

./vendor/bin/sail artisan octane:install --server=frankenphp

最後に、アプリケーションの docker-compose.yml ファイル内の laravel.test サービス定義に SUPERVISOR_PHP_COMMAND 環境変数を追加する必要があります。この環境変数には、Sail が PHP 開発サーバーの代わりに Octane を使用してアプリケーションを提供するために使用するコマンドが含まれます:

services:
laravel.test:
environment:
SUPERVISOR_PHP_COMMAND: "/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=frankenphp --host=0.0.0.0 --admin-port=2019 --port=80" # [tl! add]
XDG_CONFIG_HOME: /var/www/html/config # [tl! add]
XDG_DATA_HOME: /var/www/html/data # [tl! add]

HTTPS、HTTP/2、および HTTP/3 を有効にするには、代わりにこれらの変更を適用してください:

services:
laravel.test:
ports:
- '${APP_PORT:-80}:80'
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
- '443:443' # [tl! add]
- '443:443/udp' # [tl! add]
environment:
SUPERVISOR_PHP_COMMAND: "/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --host=localhost --port=443 --admin-port=2019 --https" # [tl! add]
XDG_CONFIG_HOME: /var/www/html/config # [tl! add]
XDG_DATA_HOME: /var/www/html/data # [tl! add]

通常、FrankenPHP Sail アプリケーションには https://localhost を介してアクセスする必要があります。https://127.0.0.1 を使用する場合は追加の設定が必要であり、推奨されていません

Docker を介した FrankenPHP

FrankenPHP の公式 Docker イメージを使用すると、静的なインストールに含まれていない追加の拡張機能を使用してパフォーマンスが向上し、FrankenPHP をネイティブでサポートしていないプラットフォームで実行するためのサポートが提供されます。公式 Docker イメージは、ローカル開発および本番環境での FrankenPHP の実行に適しています。

FrankenPHP パワードの Laravel アプリケーションをコンテナ化するための出発点として、以下の Dockerfile を使用できます:

FROM dunglas/frankenphp

RUN install-php-extensions \
pcntl
# Add other PHP extensions here...

COPY . /app

ENTRYPOINT ["php", "artisan", "octane:frankenphp"]

開発中には、次のDocker Composeファイルを使用してアプリケーションを実行できます:

# compose.yaml
services:
frankenphp:
build:
context: .
entrypoint: php artisan octane:frankenphp --max-requests=1
ports:
- "8000:8000"
volumes:
- .:/app

詳細については、公式FrankenPHPドキュメントを参照してください。

RoadRunner

RoadRunnerは、Goを使用して構築されたRoadRunnerバイナリによって動作します。RoadRunnerベースのOctaneサーバを初めて起動すると、OctaneがRoadRunnerバイナリをダウンロードしてインストールするように求められます。

Laravel Sailを介したRoadRunner

Laravel Sailを使用してアプリケーションを開発する場合は、次のコマンドを実行してOctaneとRoadRunnerをインストールする必要があります:

./vendor/bin/sail up

./vendor/bin/sail composer require laravel/octane spiral/roadrunner-cli spiral/roadrunner-http

次に、Sailシェルを起動し、rr実行可能ファイルを使用してRoadRunnerバイナリの最新のLinuxベースのビルドを取得する必要があります:

./vendor/bin/sail shell

# Within the Sail shell...
./vendor/bin/rr get-binary

その後、docker-compose.ymlファイル内のアプリケーションのlaravel.testサービス定義にSUPERVISOR_PHP_COMMAND環境変数を追加します。この環境変数には、SailがPHP開発サーバーの代わりにOctaneを使用してアプリケーションを提供するためにSailが使用するコマンドが含まれます:

services:
laravel.test:
environment:
SUPERVISOR_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=80" # [tl! add]

最後に、rrバイナリが実行可能であることを確認し、Sailイメージをビルドします:

chmod +x ./rr

./vendor/bin/sail build --no-cache

Swoole

Laravel Octaneアプリケーションを提供するためにSwooleアプリケーションサーバを使用する場合は、Swoole PHP拡張機能をインストールする必要があります。通常、これはPECLを介して行われます:

pecl install swoole

Open Swoole

Laravel Octaneアプリケーションを提供するためにOpen Swooleアプリケーションサーバを使用する場合は、Open Swoole PHP拡張機能をインストールする必要があります。通常、これはPECLを介して行われます:

pecl install openswoole

Open Swooleを使用してLaravel Octaneを使用すると、Swooleが提供する同様の機能が利用できます。これには、同時タスク、ティック、インターバルなどが含まれます。

Laravel Sailを使用したSwoole

警告

Sailを介してOctaneアプリケーションを提供する前に、最新バージョンのLaravel Sailをインストールし、アプリケーションのルートディレクトリ内で ./vendor/bin/sail build --no-cache を実行してください。

または、Laravel Sailを使用してSwooleベースのOctaneアプリケーションを開発することもできます。これは、Laravelの公式Dockerベースの開発環境です。Laravel SailにはデフォルトでSwoole拡張機能が含まれています。ただし、Sailが使用する docker-compose.yml ファイルを調整する必要があります。

始めるには、アプリケーションの docker-compose.yml ファイル内の laravel.test サービス定義に SUPERVISOR_PHP_COMMAND 環境変数を追加してください。この環境変数には、SailがPHP開発サーバーの代わりにOctaneを使用してアプリケーションを提供するために使用するコマンドが含まれます:

services:
laravel.test:
environment:
SUPERVISOR_PHP_COMMAND: "/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=swoole --host=0.0.0.0 --port=80" # [tl! add]

最後に、Sailのイメージをビルドしてください:

./vendor/bin/sail build --no-cache

Swooleの設定

必要に応じて、octane構成ファイルに追加できるいくつかの追加のSwoole構成オプションがサポートされています。これらのオプションはほとんど変更する必要がないため、デフォルトの構成ファイルには含まれていません:

'swoole' => [
'options' => [
'log_file' => storage_path('logs/swoole_http.log'),
'package_max_length' => 10 * 1024 * 1024,
],
],

アプリケーションの提供

Octaneサーバーは octane:start Artisanコマンドを使用して起動できます。デフォルトでは、このコマンドは、アプリケーションの octane 構成ファイルの server 構成オプションで指定されたサーバーを利用します:

php artisan octane:start

デフォルトでは、Octaneはポート8000でサーバーを起動するため、Webブラウザから http://localhost:8000 でアプリケーションにアクセスできます。

HTTPS経由でアプリケーションを提供

デフォルトでは、Octaneを介して実行されるアプリケーションは http:// で始まるリンクを生成します。config/octane.php 構成ファイル内で使用される OCTANE_HTTPS 環境変数は、アプリケーションをHTTPS経由で提供する場合に true に設定できます。この構成値が true に設定されている場合、Octaneはすべての生成されたリンクに https:// を付けるようにLaravelに指示します。

'https' => env('OCTANE_HTTPS', false),

Nginxを使用してアプリケーションを提供する

注記

自分自身のサーバー構成を管理する準備が整っていない場合や、堅牢なLaravel Octaneアプリケーションを実行するために必要なさまざまなサービスを設定するのが苦手な場合は、Laravel Forgeをチェックしてください。

本番環境では、OctaneアプリケーションをNginxやApacheなどの従来のウェブサーバーの背後に配置する必要があります。これにより、ウェブサーバーが画像やスタイルシートなどの静的アセットを提供し、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がインストールされていることを確認する必要があります。さらに、プロジェクト内にChokidarファイル監視ライブラリをインストールする必要があります:

npm install --save-dev chokidar

config/octane.php構成ファイル内でwatch構成オプションを使用して、監視するディレクトリやファイルを構成できます。

ワーカー数の指定

デフォルトでは、Octaneはマシンが提供する各CPUコアに対してアプリケーションリクエストワーカーを起動します。これらのワーカーは、アプリケーションに入る着信HTTPリクエストを処理するために使用されます。octane:startコマンドを呼び出す際に--workersオプションを使用して、手動で開始するワーカーの数を指定できます。

php artisan octane:start --workers=4

Swooleアプリケーションサーバーを使用している場合、開始する"タスクワーカー"の数を指定することもできます:

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

最大リクエスト数の指定

迷子のメモリリークを防ぐために、Octaneは1つのワーカーが500リクエストを処理した後に優雅に再起動します。この数値を調整するには、--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はリクエストを処理する間、アプリケーションを1度起動し、メモリに保持します。そのため、アプリケーションを構築する際に考慮すべき点がいくつかあります。たとえば、アプリケーションのサービスプロバイダーのregisterおよびbootメソッドは、リクエストワーカーが最初に起動するときにのみ実行されます。後続のリクエストでは、同じアプリケーションインスタンスが再利用されます。

このため、オブジェクトのコンストラクタにアプリケーションサービスコンテナまたはリクエストを注入する際に特に注意する必要があります。これにより、そのオブジェクトは後続のリクエストでコンテナやリクエストの古いバージョンを持つ可能性があります。

Octaneは、リクエスト間で第一のフレームワーク状態を自動的にリセットします。ただし、Octaneは常にアプリケーションによって作成されたグローバル状態をリセットする方法を知らない場合があります。そのため、Octaneに対応した方法でアプリケーションを構築する方法を把握しておく必要があります。以下では、Octaneを使用する際に問題を引き起こす可能性のある最も一般的な状況について説明します。

コンテナーのインジェクション

一般的には、他のオブジェクトのコンストラクタにアプリケーションサービスコンテナやHTTPリクエストインスタンスをインジェクトすることは避けるべきです。例えば、次のバインディングは、シングルトンとしてバインドされたオブジェクトにアプリケーションサービスコンテナ全体をインジェクトします:

use App\Service;
use Illuminate\Contracts\Foundation\Application;

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

この例では、Service インスタンスがアプリケーションの起動プロセス中に解決される場合、コンテナがサービスにインジェクトされ、その同じコンテナが後続のリクエストで Service インスタンスによって保持されます。これは特定のアプリケーションにとって問題にならないかもしれませんが、ブートサイクル中に後から追加されたバインディングが欠落する可能性があるか、後続のリクエストによって追加されたバインディングが欠落する可能性があります。

回避策として、バインディングをシングルトンとして登録するのをやめるか、常に現在のコンテナインスタンスを解決するコンテナリゾルバクロージャをサービスにインジェクトすることができます:

use App\Service;
use Illuminate\Container\Container;
use Illuminate\Contracts\Foundation\Application;

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

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

グローバルな app ヘルパーや Container::getInstance() メソッドは常に最新バージョンのアプリケーションコンテナを返します。

リクエストのインジェクション

一般的には、他のオブジェクトのコンストラクタにアプリケーションサービスコンテナやHTTPリクエストインスタンスをインジェクトすることは避けるべきです。例えば、次のバインディングは、シングルトンとしてバインドされたオブジェクトにリクエストインスタンス全体をインジェクトします:

use App\Service;
use Illuminate\Contracts\Foundation\Application;

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

この例では、Service インスタンスがアプリケーションの起動プロセス中に解決される場合、HTTPリクエストがサービスにインジェクトされ、その同じリクエストが後続のリクエストで Service インスタンスによって保持されます。そのため、すべてのヘッダー、入力、およびクエリ文字列データが不正確になり、その他のリクエストデータも同様です。

回避策として、バインディングをシングルトンとして登録するのをやめるか、常に現在のリクエストインスタンスを解決するリクエストリゾルバクロージャをサービスにインジェクトすることができます。また、最も推奨されるアプローチは、単にオブジェクトが実行時に必要とする特定のリクエスト情報をオブジェクトのメソッドの1つに渡すことです。

use App\Service;
use Illuminate\Contracts\Foundation\Application;

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

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

// Or...

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

グローバルrequestヘルパーは、アプリケーションが現在処理しているリクエストを常に返し、したがってアプリケーション内で安全に使用できます。

警告

コントローラーメソッドやルートクロージャーでIlluminate\Http\Requestインスタンスを型ヒントすることは許容されます。

設定リポジトリのインジェクション

一般的に、他のオブジェクトのコンストラクタに設定リポジトリインスタンスをインジェクトすることは避けるべきです。例えば、次のバインディングは、設定リポジトリをシングルトンとしてバインドされたオブジェクトにインジェクトします:

use App\Service;
use Illuminate\Contracts\Foundation\Application;

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

この例では、リクエスト間で設定値が変更されると、そのサービスは新しい値にアクセスできなくなります。なぜなら、元のリポジトリインスタンスに依存しているからです。

回避策として、バインディングをシングルトンとして登録するのをやめるか、クラスに設定リポジトリリゾルバクロージャーをインジェクトすることができます:

use App\Service;
use Illuminate\Container\Container;
use Illuminate\Contracts\Foundation\Application;

$this->app->bind(Service::class, function (Application $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.
*/
public function index(Request $request): array
{
Service::$data[] = Str::random(10);

return [
// ...
];
}

アプリケーションを構築する際には、この種のメモリリークを作成しないよう特に注意する必要があります。新しいメモリリークをアプリケーションに導入していないかを確認するために、ローカル開発中にアプリケーションのメモリ使用量を監視することが推奨されます。

並行タスク

警告

この機能にはSwooleが必要です。

Swooleを使用すると、軽量なバックグラウンドタスクを介して操作を並行して実行できます。Octaneのconcurrentlyメソッドを使用してこれを実行できます。このメソッドをPHPの配列デストラクチャリングと組み合わせて、各操作の結果を取得できます:

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

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

Octaneが処理する同時タスクは、Swooleの「タスクワーカー」を利用し、着信リクエストとは完全に異なるプロセスで実行されます。同時タスクを処理するためのワーカーの数は、octane:startコマンドの--task-workersディレクティブによって決定されます:

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

concurrentlyメソッドを呼び出す際には、Swooleのタスクシステムによって課せられた制限のため、1024以上のタスクを提供しないでください。

Ticks and Intervals

警告

この機能にはSwooleが必要です。

Swooleを使用する際には、指定された秒数ごとに実行される「tick」操作を登録することができます。tickメソッドを介して「tick」コールバックを登録できます。tickメソッドに提供される最初の引数は、ティッカーの名前を表す文字列である必要があります。2番目の引数は、指定された間隔で呼び出されるコールバック関数である必要があります。

この例では、10秒ごとに呼び出されるクロージャを登録します。通常、tickメソッドは、アプリケーションのサービスプロバイダのbootメソッド内で呼び出す必要があります:

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

immediateメソッドを使用すると、Octaneに対して、Octaneサーバーが最初に起動されたときに即座にティックコールバックを呼び出し、その後N秒ごとに呼び出すように指示できます:

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

The Octane Cache

警告

この機能にはSwooleが必要です。

Swooleを使用する際には、Octaneキャッシュドライバを活用することができます。このドライバは、1秒あたり最大200万回の操作を提供する読み書き速度を提供します。そのため、このキャッシュドライバは、キャッシュレイヤーから極端な読み取り/書き込み速度が必要なアプリケーションにとって優れた選択肢です。

このキャッシュドライバは、Swoole tablesによって提供されています。キャッシュに格納されたすべてのデータは、サーバー上のすべてのワーカーで利用できます。ただし、サーバーが再起動されると、キャッシュされたデータはフラッシュされます:```

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

Octane キャッシュ内のエントリ数の最大値は、アプリケーションの octane 構成ファイルで定義できます。

キャッシュ間隔

Laravel のキャッシュシステムで提供される通常のメソッドに加えて、Octane キャッシュドライバには間隔ベースのキャッシュがあります。これらのキャッシュは指定された間隔で自動的に更新され、アプリケーションのサービスプロバイダの boot メソッド内に登録する必要があります。たとえば、次のキャッシュは5秒ごとに更新されます:

use Illuminate\Support\Str;

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

テーブル

警告

この機能には Swoole が必要です。

Swoole を使用すると、独自の任意の Swoole テーブル を定義して操作することができます。Swoole テーブルは非常に高いパフォーマンスを提供し、これらのテーブル内のデータはサーバー上のすべてのワーカーからアクセスできます。ただし、サーバーが再起動されると、それらのテーブル内のデータは失われます。

テーブルは、アプリケーションの octane 構成ファイルの tables 構成配列内で定義する必要があります。最大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 テーブルでサポートされる列タイプは、stringintfloat です。