ひでメモ

プログラムについて勉強したことを書きます。たぶん。

【Laravel】Sail のデフォルト Web/AP サーバで複数リクエストを並列処理する

概要

Laravel Sail では複数のリクエストを並列で処理できないかと思ったら実はできました!
ついでに開発環境もちょっとだけ早くなったよ、という話です。

Laravel Sail 便利ですよね

現在のプロジェクトの開発環境は Laravel Sail を使用しています。

readouble.com

Sail を使用すれば簡単に Laravel の Docker 開発環境が作れます。

また、docker compose ~~~ のコマンドが sail up のようにデフォルトでエイリアスが作られていて簡単に叩けるようになっていたりして便利です。
例えば、sail artisanに続けてコマンドを実行すれば migratetinkerなどがコンテナに入らずに実行できます!

このように便利な Sail なのですが先日ひとつ問題が発生しました。

APIタイムアウトするという事象が発生

システムA から システムB へ API で連携する改修を行っていました。
その中で以下のように相互に API を叩き合う処理を追加し試したところ処理が終わらないということが発生しました。

  1. システムAがBのAPI1を実行
  2. システムBはそのAPI1の処理の途中で、システムAのAPI2を実行
  3. システムBからの応答がなかったとしてシステムAの処理がタイムアウト

タイムアウトの原因

このタイムアウトの原因は Laravel Sail の Web/AP サーバがシングルプロセスだったためでした。

以下のようにお互いがお互いの処理完了を待ってしまった結果、タイムアウトしてしまいました。

  1. システムAはAPI1の応答を待っている ※この時点でひとつしかないプロセスを専有
  2. システムBはAPI1の途中でAPI2で情報を取得しようとするが、システムAはシングルプロセスなのでこれに応答できない

ただ、実装を見直した結果、相互にAPIを叩き合う必要はなかったのでこの問題は回避できました。

なんでシングルプロセスなの?

Laravel Sail は Web/AP サーバに PHP のビルドインサーバを使用しており、こちらが基本的にはシングルプロセスでしか動作しないためでした。

PHP: ビルトインウェブサーバー - Manual

マニュアルの一番上に書いてありますね… 残念…

と思ったら実はできそう

この記事を書いていて気づいてしまったのですが、PHP7.4 以降であれば環境変数を指定することで並列で処理を実行できるようです…!
一番上に「単一のシングルスレッドプロセスしか実行しない」って書いてあったから騙された…!

ビルトインウェブサーバに対して複数のリクエストを並列で投げる必要があるテストコードのために、 複数のワーカーをフォークさせるよう設定できるようになりました。
サーバを起動する前に欲しいワーカーの数を PHP_CLI_SERVER_WORKERS 環境変数に設定してください。

試してみました

docker-compose.yamlに以下のようにPHP_CLI_SERVER_WORKERS環境変数を追加してコンテナを起動してみました。

        environment:
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
            PHP_CLI_SERVER_WORKERS: 5  # 追加!

必ず呼び出される index.php などに sleep で5秒待機する処理を追加して、curl で同じ URL を取得するように複数のタブで並列に叩いてみました。
その結果、PHP_CLI_SERVER_WORKERSを指定した場合だと並列で curl を実行してもほぼ同じタイミングで応答が返ってきました!
環境変数を指定しない場合だと同タイミングではなく、先に叩いた curl の応答が返ってきた数秒後に次の応答が返ってきました)

少しだけ高速化

ふと思って開発環境で画面を開いて見たところ1〜2秒くらいですが表示速度が上がっていました。

特に意識してなかったのですが、今まではシングルプロセスだったのでフロントから並列で叩かれるAPIも直列で処理していたわけです。
これが、並列で処理して応答を返してくれるようになったので表示速度が少しだけあがりました!

ただ、あまり並列数を上げすぎるとどこかで処理が集中しすぎるのか応答が返ってこない API が出てくるためプロセス数は 3 程度に抑えるようにしました。

開発環境でも早いに越したことことはないのでラッキーでした!

おまけ:どこに Sail はビルドインサーバで動いてるって書いてるの?

ここの Tips に Sail で php artisan serve が動いているという記載がありました。

Laravel Sail 8.x Laravel

そしてこちらのページにはSailへPHP開発サーバの代わりにOctaneを使いとありました。

Laravel Octane 8.x Laravel

もっとわかりやすく書いてくれていたページがあった気がしたのですが見つけられなかった…!