コンテンツへスキップ

Laravel Octane

導入

Laravel Octane は、FrankenPHPOpen SwooleSwooleRoadRunner などの高性能アプリケーションサーバーを使用してアプリケーションを提供することにより、アプリケーションのパフォーマンスを飛躍的に向上させます。Octaneはアプリケーションを一度起動し、メモリに保持し、その後超音速でリクエストを処理します。

インストール

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

composer require laravel/octane

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

php artisan octane:install

サーバーの要件

exclamation

Laravel OctaneにはPHP 8.1以降が必要です。

FrankenPHP

FrankenPHP はGoで記述されたPHPアプリケーションサーバーであり、アーリーヒント、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環境変数を追加します。この環境変数には、PHP開発サーバーではなくOctaneを使用してアプリケーションを提供するためにSailが使用するコマンドが含まれます。

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='${APP_PORT:-80}'"
XDG_CONFIG_HOME: /var/www/html/config
XDG_DATA_HOME: /var/www/html/data

HTTPS、HTTP/2、HTTP/3を有効にするには、代わりにこれらの変更を適用します。

services:
laravel.test:
ports:
- '${APP_PORT:-80}:80'
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
- '443:443'
- '443:443/udp'
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"
XDG_CONFIG_HOME: /var/www/html/config
XDG_DATA_HOME: /var/www/html/data

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

Docker経由でのFrankenPHP

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

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 --workers=1 --max-requests=1
ports:
- "8000:8000"
volumes:
- .:/app

--log-levelオプションがphp artisan octane:startコマンドに明示的に渡された場合、OctaneはFrankenPHPのネイティブロガーを使用し、別途設定されていない限り、構造化されたJSONログを出力します。

DockerでFrankenPHPを実行する方法の詳細については、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環境変数を追加します。この環境変数には、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='${APP_PORT:-80}'"

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

chmod +x ./rr
 
./vendor/bin/sail build --no-cache

Swoole

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

pecl install swoole

Open Swoole

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

pecl install openswoole

Laravel OctaneでOpen Swooleを使用すると、並行タスク、ティック、インターバルなど、Swooleによって提供されるのと同じ機能が提供されます。

Laravel Sail経由でのSwoole

exclamation

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

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

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

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='${APP_PORT:-80}'"

最後に、Sailイメージをビルドします。

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

Swooleの設定

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

'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はLaravelにすべての生成されたリンクにhttps://のプレフィックスを付けるように指示します。

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

Nginx経由でのアプリケーションの提供

lightbulb

独自のサーバー設定を管理する準備ができていない場合、または堅牢なLaravel Octaneアプリケーションを実行するために必要なさまざまなサービスすべてを設定することに慣れていない場合は、Laravel Forgeをご覧ください。

本番環境では、NginxやApacheなどの従来型のWebサーバーの背後で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がインストールされていることを確認してください。さらに、プロジェクトに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はワーカーが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はアプリケーションを一度起動し、リクエストを提供している間メモリに保持するため、アプリケーションを構築する際に考慮すべきいくつかの注意点があります。たとえば、アプリケーションのサービスプロバイダーの`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`ヘルパーは、アプリケーションが現在処理しているリクエストを常に返し、したがってアプリケーション内で安全に使用できます。

exclamation

コントローラーメソッドとルートクロージャで`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 [
// ...
];
}

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

並行タスク

exclamation

この機能には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個を超えるタスクを指定しないでください。

ティックとインターバル

exclamation

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

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

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

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

`immediate`メソッドを使用すると、Octaneサーバーが最初に起動したときに、そしてその後N秒ごとに、tickコールバックをすぐに呼び出すように指示できます。

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

Octaneキャッシュ

exclamation

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

Swooleを使用すると、Octaneキャッシュドライバーを利用できます。これは、毎秒最大200万回の読み取り/書き込み速度を提供します。そのため、このキャッシュドライバーは、キャッシングレイヤーから非常に高速な読み取り/書き込み速度を必要とするアプリケーションに最適な選択肢です。

このキャッシュドライバーはSwooleテーブルによって提供されています。キャッシュに保存されているすべてのデータは、サーバー上のすべてのワーカーからアクセスできます。ただし、サーバーが再起動されると、キャッシュされたデータはフラッシュされます。

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

Octaneキャッシュで許可される最大エントリ数は、アプリケーションの`octane`設定ファイルで定義できます。

キャッシュ間隔

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

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

テーブル

exclamation

この機能には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');
exclamation

Swooleテーブルでサポートされている列タイプは、`string`、`int`、`float`です。