Laravel Octane
導入
Laravel Octane は、FrankenPHP、Open Swoole、Swoole、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アプリケーションサーバーであり、アーリーヒント、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.yamlservices: 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
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経由でのアプリケーションの提供
独自のサーバー設定を管理する準備ができていない場合、または堅牢な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`ヘルパーは、アプリケーションが現在処理しているリクエストを常に返し、したがってアプリケーション内で安全に使用できます。
コントローラーメソッドとルートクロージャで`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個を超えるタスクを指定しないでください。
ティックとインターバル
この機能には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キャッシュ
この機能にはSwooleが必要です。
Swooleを使用すると、Octaneキャッシュドライバーを利用できます。これは、毎秒最大200万回の読み取り/書き込み速度を提供します。そのため、このキャッシュドライバーは、キャッシングレイヤーから非常に高速な読み取り/書き込み速度を必要とするアプリケーションに最適な選択肢です。
このキャッシュドライバーはSwooleテーブルによって提供されています。キャッシュに保存されているすべてのデータは、サーバー上のすべてのワーカーからアクセスできます。ただし、サーバーが再起動されると、キャッシュされたデータはフラッシュされます。
Cache::store('octane')->put('framework', 'Laravel', 30);
Octaneキャッシュで許可される最大エントリ数は、アプリケーションの`octane`設定ファイルで定義できます。
キャッシュ間隔
Laravelのキャッシュシステムによって提供される一般的なメソッドに加えて、Octaneキャッシュドライバーには、間隔ベースのキャッシュ機能があります。これらのキャッシュは指定された間隔で自動的に更新され、アプリケーションのサービスプロバイダーの1つの`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テーブルでサポートされている列タイプは、`string`、`int`、`float`です。