はじめに

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

インストール

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

  1. composer require laravel/octane

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

  1. 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をインストールするために次のコマンドを実行する必要があります:

  1. ./vendor/bin/sail up
  2. ./vendor/bin/sail composer require laravel/octane

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

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

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

  1. services:
  2. laravel.test:
  3. environment:
  4. 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"
  5. XDG_CONFIG_HOME: /var/www/html/config
  6. XDG_DATA_HOME: /var/www/html/data

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

  1. services:
  2. laravel.test:
  3. ports:
  4. - '${APP_PORT:-80}:80'
  5. - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
  6. - '443:443'
  7. - '443:443/udp'
  8. environment:
  9. SUPERVISOR_PHP_COMMAND: "/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --host=localhost --port=443 --admin-port=2019 --https"
  10. XDG_CONFIG_HOME: /var/www/html/config
  11. XDG_DATA_HOME: /var/www/html/data

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

Dockerを介したFrankenPHP

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

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

  1. FROM dunglas/frankenphp
  2. RUN install-php-extensions \
  3. pcntl
  4. # Add other PHP extensions here...
  5. COPY . /app
  6. ENTRYPOINT ["php", "artisan", "octane:frankenphp"]

次に、開発中にアプリケーションを実行するために次のDocker Composeファイルを利用できます:

  1. # compose.yaml
  2. services:
  3. frankenphp:
  4. build:
  5. context: .
  6. entrypoint: php artisan octane:frankenphp --workers=1 --max-requests=1
  7. ports:
  8. - "8000:8000"
  9. volumes:
  10. - .:/app

公式FrankenPHPドキュメントを参照して、DockerでFrankenPHPを実行する方法についての詳細を確認できます。

RoadRunner

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

Laravel Sailを介したRoadRunner

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

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

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

  1. ./vendor/bin/sail shell
  2. # Sailシェル内で...
  3. ./vendor/bin/rr get-binary

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

  1. services:
  2. laravel.test:
  3. environment:
  4. 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"

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

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

Swoole

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

  1. pecl install swoole

Open Swoole

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

  1. 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 SailにはデフォルトでSwoole拡張が含まれています。ただし、Sailで使用されるdocker-compose.ymlファイルを調整する必要があります。

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

  1. services:
  2. laravel.test:
  3. environment:
  4. 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"

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

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

Swooleの設定

Swooleには、必要に応じてoctane設定ファイルに追加できるいくつかの追加設定オプションがあります。これらのオプションは、通常変更する必要がないため、デフォルトの設定ファイルには含まれていません:

  1. 'swoole' => [
  2. 'options' => [
  3. 'log_file' => storage_path('logs/swoole_http.log'),
  4. 'package_max_length' => 10 * 1024 * 1024,
  5. ],
  6. ],

アプリケーションの提供

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

  1. php artisan octane:start

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

HTTPSを介したアプリケーションの提供

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

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

Nginxを介したアプリケーションの提供

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

本番環境では、OctaneアプリケーションをNginxやApacheなどの従来のWebサーバーの背後で提供する必要があります。これにより、Webサーバーが画像やスタイルシートなどの静的アセットを提供し、SSL証明書の終了を管理できます。

以下のNginx設定例では、Nginxはサイトの静的アセットを提供し、ポート8000で実行されているOctaneサーバーにリクエストをプロキシします:

  1. map $http_upgrade $connection_upgrade {
  2. default upgrade;
  3. '' close;
  4. }
  5. server {
  6. listen 80;
  7. listen [::]:80;
  8. server_name domain.com;
  9. server_tokens off;
  10. root /home/forge/domain.com/public;
  11. index index.php;
  12. charset utf-8;
  13. location /index.php {
  14. try_files /not_exists @octane;
  15. }
  16. location / {
  17. try_files $uri $uri/ @octane;
  18. }
  19. location = /favicon.ico { access_log off; log_not_found off; }
  20. location = /robots.txt { access_log off; log_not_found off; }
  21. access_log off;
  22. error_log /var/log/nginx/domain.com-error.log error;
  23. error_page 404 /index.php;
  24. location @octane {
  25. set $suffix "";
  26. if ($uri = /index.php) {
  27. set $suffix ?$query_string;
  28. }
  29. proxy_http_version 1.1;
  30. proxy_set_header Host $http_host;
  31. proxy_set_header Scheme $scheme;
  32. proxy_set_header SERVER_PORT $server_port;
  33. proxy_set_header REMOTE_ADDR $remote_addr;
  34. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  35. proxy_set_header Upgrade $http_upgrade;
  36. proxy_set_header Connection $connection_upgrade;
  37. proxy_pass http://127.0.0.1:8000$suffix;
  38. }
  39. }

ファイル変更の監視

Octaneサーバーが起動すると、アプリケーションは一度メモリにロードされるため、アプリケーションのファイルに対する変更はブラウザを更新しても反映されません。たとえば、routes/web.phpファイルに追加されたルート定義は、サーバーが再起動されるまで反映されません。便利なことに、--watchフラグを使用して、Octaneにアプリケーション内のファイル変更があるたびにサーバーを自動的に再起動するよう指示できます:

  1. php artisan octane:start --watch

この機能を使用する前に、Nodeがローカル開発環境にインストールされていることを確認してください。さらに、プロジェクト内にChokidarファイル監視ライブラリをインストールする必要があります:

  1. npm install --save-dev chokidar

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

ワーカー数の指定

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

  1. php artisan octane:start --workers=4

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

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

最大リクエスト数の指定

不要なメモリリークを防ぐために、Octaneは500リクエストを処理した後にワーカーを優雅に再起動します。この数を調整するには、--max-requestsオプションを使用できます:

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

ワーカーの再読み込み

Octaneサーバーのアプリケーションワーカーを優雅に再起動するには、octane:reloadコマンドを使用します。通常、これはデプロイ後に行うべきであり、新しくデプロイされたコードがメモリに読み込まれ、以降のリクエストに提供されるようにします:

  1. php artisan octane:reload

サーバーの停止

Octaneサーバーを停止するには、octane:stop Artisanコマンドを使用します:

  1. php artisan octane:stop

サーバーの状態を確認

Octaneサーバーの現在の状態を確認するには、octane:status Artisanコマンドを使用します:

  1. php artisan octane:status

依存性注入とOctane

Octaneはアプリケーションを一度起動し、リクエストを処理している間メモリに保持するため、アプリケーションを構築する際に考慮すべきいくつかの注意点があります。たとえば、アプリケーションのサービスプロバイダーのregisterおよびbootメソッドは、リクエストワーカーが最初に起動したときに一度だけ実行されます。以降のリクエストでは、同じアプリケーションインスタンスが再利用されます。

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

Octaneはリクエスト間でのファーストパーティフレームワークの状態のリセットを自動的に処理します。ただし、Octaneはアプリケーションによって作成されたグローバル状態をリセットする方法を常に知っているわけではありません。したがって、Octaneに優しい方法でアプリケーションを構築する方法を理解しておく必要があります。以下では、Octaneを使用する際に問題を引き起こす可能性のある最も一般的な状況について説明します。

コンテナ注入

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

  1. use App\Service;
  2. use Illuminate\Contracts\Foundation\Application;
  3. /**
  4. * Register any application services.
  5. */
  6. public function register(): void
  7. {
  8. $this->app->singleton(Service::class, function (Application $app) {
  9. return new Service($app);
  10. });
  11. }

この例では、Serviceインスタンスがアプリケーションの起動プロセス中に解決されると、コンテナがサービスに注入され、その同じコンテナが以降のリクエストでServiceインスタンスによって保持されます。これは、特定のアプリケーションにとって問題ではないかもしれませんが、起動サイクルの後半や以降のリクエストで追加されたバインディングがコンテナに見つからないという予期しない問題を引き起こす可能性があります。

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

  1. use App\Service;
  2. use Illuminate\Container\Container;
  3. use Illuminate\Contracts\Foundation\Application;
  4. $this->app->bind(Service::class, function (Application $app) {
  5. return new Service($app);
  6. });
  7. $this->app->singleton(Service::class, function () {
  8. return new Service(fn () => Container::getInstance());
  9. });

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

リクエスト注入

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

  1. use App\Service;
  2. use Illuminate\Contracts\Foundation\Application;
  3. /**
  4. * Register any application services.
  5. */
  6. public function register(): void
  7. {
  8. $this->app->singleton(Service::class, function (Application $app) {
  9. return new Service($app['request']);
  10. });
  11. }

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

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

  1. use App\Service;
  2. use Illuminate\Contracts\Foundation\Application;
  3. $this->app->bind(Service::class, function (Application $app) {
  4. return new Service($app['request']);
  5. });
  6. $this->app->singleton(Service::class, function (Application $app) {
  7. return new Service(fn () => $app['request']);
  8. });
  9. // Or...
  10. $service->method($request->input('name'));

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

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

設定リポジトリの注入

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

  1. use App\Service;
  2. use Illuminate\Contracts\Foundation\Application;
  3. /**
  4. * Register any application services.
  5. */
  6. public function register(): void
  7. {
  8. $this->app->singleton(Service::class, function (Application $app) {
  9. return new Service($app->make('config'));
  10. });
  11. }

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

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

  1. use App\Service;
  2. use Illuminate\Container\Container;
  3. use Illuminate\Contracts\Foundation\Application;
  4. $this->app->bind(Service::class, function (Application $app) {
  5. return new Service($app->make('config'));
  6. });
  7. $this->app->singleton(Service::class, function () {
  8. return new Service(fn () => Container::getInstance()->make('config'));
  9. });

グローバルconfigは、常に設定リポジトリの最新バージョンを返すため、アプリケーション内で安全に使用できます。

メモリリークの管理

Octaneはリクエスト間でアプリケーションをメモリに保持するため、静的に維持される配列にデータを追加するとメモリリークが発生します。たとえば、次のコントローラーはメモリリークを持っています。なぜなら、アプリケーションへの各リクエストが静的$data配列にデータを追加し続けるからです:

  1. use App\Service;
  2. use Illuminate\Http\Request;
  3. use Illuminate\Support\Str;
  4. /**
  5. * Handle an incoming request.
  6. */
  7. public function index(Request $request): array
  8. {
  9. Service::$data[] = Str::random(10);
  10. return [
  11. // ...
  12. ];
  13. }

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

同時タスク

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

Swooleを使用する場合、軽量のバックグラウンドタスクを介して操作を同時に実行できます。これは、Octaneのconcurrentlyメソッドを使用して実現できます。このメソッドをPHPの配列分解と組み合わせて、各操作の結果を取得できます:

  1. use App\Models\User;
  2. use App\Models\Server;
  3. use Laravel\Octane\Facades\Octane;
  4. [$users, $servers] = Octane::concurrently([
  5. fn () => User::all(),
  6. fn () => Server::all(),
  7. ]);

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

  1. php artisan octane:start --workers=4 --task-workers=6
  1. <a name="ticks-and-intervals"></a>
  2. ## ティックと間隔
  3. この機能には[Swoole](#swoole)が必要です。
  4. Swooleを使用する場合、指定された秒数ごとに実行される「ティック」操作を登録できます。`````tick`````メソッドを介して「ティック」コールバックを登録できます。`````tick`````メソッドに提供される最初の引数は、ティッカーの名前を表す文字列である必要があります。2番目の引数は、指定された間隔で呼び出されるコール可能なものである必要があります。
  5. この例では、10秒ごとに呼び出されるクロージャを登録します。通常、`````tick`````メソッドは、アプリケーションのサービスプロバイダーの`````boot`````メソッド内で呼び出されるべきです:
  6. ``````php
  7. Octane::tick('simple-ticker', fn () => ray('Ticking...'))
  8. ->seconds(10);
  9. `
  1. ``````php
  2. Octane::tick('simple-ticker', fn () => ray('Ticking...'))
  3. ->seconds(10)
  4. ->immediate();
  5. `

Octaneキャッシュ

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

Swooleを使用する場合、読み取りおよび書き込み速度が毎秒200万オペレーションに達するOctaneキャッシュドライバーを利用できます。したがって、このキャッシュドライバーは、キャッシュレイヤーから極端な読み取り/書き込み速度を必要とするアプリケーションにとって優れた選択肢です。

このキャッシュドライバーは Swooleテーブルによって動作します。キャッシュに保存されたすべてのデータは、サーバー上のすべてのワーカーが利用できます。ただし、サーバーが再起動されるとキャッシュデータはフラッシュされます:

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

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

キャッシュ間隔

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

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

テーブル

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

Swooleを使用する場合、独自の任意のSwooleテーブルを定義して操作できます。Swooleテーブルは極端なパフォーマンススループットを提供し、これらのテーブル内のデータはサーバー上のすべてのワーカーがアクセスできます。ただし、サーバーが再起動されると、内部のデータは失われます。

テーブルは、アプリケーションのoctane設定ファイルのtables設定配列内で定義する必要があります。最大1000行を許可するテーブルがすでに構成されています。文字列列の最大サイズは、以下のように列の型の後に列サイズを指定することで構成できます:

  1. 'tables' => [
  2. 'example:1000' => [
  3. 'name' => 'string:1000',
  4. 'votes' => 'int',
  5. ],
  6. ],

テーブルにアクセスするには、Octane::tableメソッドを使用できます:

  1. use Laravel\Octane\Facades\Octane;
  2. Octane::table('example')->set('uuid', [
  3. 'name' => 'Nuno Maduro',
  4. 'votes' => 1000,
  5. ]);
  6. return Octane::table('example')->get('uuid');

Swooleテーブルでサポートされている列の型は、stringintfloatです。