2015年5月にはHTTP/2が始まっており、2022年6月からはHTTP/3が始まっているというのに、ホームラボはHTTP/1.1のままだった。
まずは、HTTP/2でサービス提供できるようにしよう。
いくつかのサイトで、設定からパフォーマンスチューニングまで教えてくれている。
Hacker's High / php-fpm の設定を理解してサイトのパフォーマンスを向上させる
Qiita / Ubuntu20.04 と Apache2 で HTTP/2 化
ただ、読んでもよくわからない。
諸兄が教えてくれるこれらを理解するために、背景となる知識が必要だ。
設定の概要
ホームラボにはいくつかサーバーがあるが、PHPが入っている・入っていないの違いでちょっと動きが違ったので、その観点で書いてみる。
※Rubyの場合にはまた違った設定が必要かもしれないが、必要になったときに頑張る方向。
やろうとすることを整理してみると、
- ApacheがHTTP/2を取り扱えるようにする。(mod_http2.so)
- Apacheのマルチプロセッシングモジュール(MPM)を、マルチプロセス・マルチスレッドのものに切り替える。(mod_mpm_event.so)
- ApacheのMPMが作業を渡せるようにする。(mod_proxy_fcgi.so, mod_proxy.so)
- ApacheのMPMに具体的な作業の渡し方を知らせる。(php8.1-fpm.conf)
- Apacheから作業を受け取って処理するリスナーを設置する。(PHP 8.1 FastCGI Process Manager)
- チューニング。ここでいうチューニングは最低限のもので、大量アクセスに対応するチューニングを指してはいない。
ということで、考えていたよりも多かった。
まず、HTTP/2はHTTP/1.1と違って、リクエストを並行して扱うことができるプロトコルになった。
mdn web docs / HTTP の進化 HTTP/2 - 高パフォーマンスなプロトコル 参照
一方、ApacheはリクエストをMPMで受け付けて処理する。
MPMはOSに最適なものが提供されており、UNIXではprefork、worker、eventの3つがある。このうちのどれか1つをロードする必要がある。
MPMは、ネットワークポートのバインド、リクエストの受け付け、子プロセスの割り当てを行う主役と言っても良い機能で、このような特徴がある。
スレッドをサポート | スレッドセーフな ポーリングをサポート | デフォルトのMPM | ポイント |
---|---|---|---|
NO | NO | prefork | スレッド化されていないサーバーを実装している。スレッド化を避ける必要がある場合に適する。 MaxRequestWorkersを予想される同時リクエストより大きく、すべてのプロセスがメモリを確保できるように小さく設定することが重要。 |
YES | NO | worker | マルチプロセス・マルチスレッドサーバーを実装している。 ThreadsPerChildで子プロセスが展開するスレッドの数を制御し、MaxRequestWorkersで起動可能なスレッドの最大総数を制御することが重要。 |
YES | YES | event | workerベースの実装で、パフォーマンスが良い。 イマドキのOSの多くは、スレッドとスレッドセーフなポーリングをサポートするので、これがデフォルトになる。 リスナースレッドに作業を渡すことで、より多くのリクエストを同時に処理できるようにしている。 |
並行したリクエストはスレッドで処理するようなので、HTTP/2が並列で多くのリクエストを送信するプロトコルであることから、preforkは向いていないので(できるけれども厳しい制限)、eventを設定するのがベスト。
そして、MPMにeventを使用するならば、作業を渡すリスナーを設置する必要がある。
以上のように大掛かりな仕掛けになってしまうが、並列で要求を処理できるとページの読み込みスピードは上がるので、設定する価値はあるかもしれない。
なお、ブラウザはHTTPSでないとHTTP/2の通信をしない。
今回の記事ではSSLの設定をサボっているので、curlコマンドを使ってHTTP/2の通信ができるようになるところまで確認しているが、サービスを公開するならSSLの設定が必要。
PHPを使用していない環境
ほぼまっさらな環境で試したが、この場合はMPMがデフォルトでeventになっており、HTTP/2を有効にすれば良かった。
まず、Apacheをインストール。
$ sudo apt -y install apache2 $ apache2 -v Server version: Apache/2.4.52 (Ubuntu) Server built: 2023-03-01T22:43:55
http2モジュールを有効化する。
$ sudo a2enmod http2 $ sudo systemctl restart apache2
ヘッダーを確認してみる。
$ curl --http2 --head http://localhost HTTP/1.1 101 Switching Protocols Upgrade: h2c Connection: Upgrade HTTP/2 200 last-modified: Sat, 27 May 2023 05:34:11 GMT etag: W/"29af-5fca6340f6d01" accept-ranges: bytes content-length: 10671 vary: Accept-Encoding content-type: text/html date: Sun, 00 Jan 1900 00:00:00 GMT server: Apache/2.4.52 (Ubuntu)
HTTP/2で通信ができるようになっている。
PHPを使用している環境
状態の確認
テスト環境として、後述の手順でWordPressをインストールした。
この場合は、MPMがpreforkになっている。
$ apachectl -M ... mpm_prefork_module (shared) ...
レスポンスを確認すると、HTTP/1.1での通信になっている。
誰かに教えてもらった手順で普通にWordPressをインストールすると、大体こんな状態になっているのではなかろうか。
$ curl --http2 --head http://localhost HTTP/1.1 200 OK Date: Sat, 27 May 2023 09:35:13 GMT Server: Apache/2.4.52 (Ubuntu) Link: <http://script.hogeserver.hogeddns.jp/wp-json/>; rel="https://api.w.org/" Content-Type: text/html; charset=UTF-8
HTTP/2を有効にする
作業を受け取るリスナーを設置する。
$ sudo apt install php-fpm
php-fpm(実態はphp8.1-fpm)はサービスで、設定ファイルが/etc/php/8.1/fpm/php-fpm.confに見える。
また、pool wwwというのが2つあること、ドメインソケットが開いていることがわかる。
$ systemctl status php8.1-fpm.service ● php8.1-fpm.service - The PHP 8.1 FastCGI Process Manager Loaded: loaded (/lib/systemd/system/php8.1-fpm.service; enabled; vendor preset: enabled) Active: active (running) since Sat 2023-05-27 09:50:20 UTC; 14h ago Docs: man:php-fpm8.1(8) Process: 97480 ExecStartPost=/usr/lib/php/php-fpm-socket-helper install /run/php/php-fpm.sock /etc/php/8.1/fpm/pool.d/www.conf 81 (code=exited, status=0/SUCCESS) Main PID: 97477 (php-fpm8.1) Status: "Processes active: 0, idle: 2, Requests: 60, slow: 0, Traffic: 0req/sec" Tasks: 3 (limit: 4530) Memory: 52.2M CPU: 3.493s CGroup: /system.slice/php8.1-fpm.service ├─97477 "php-fpm: master process (/etc/php/8.1/fpm/php-fpm.conf)" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ├─97478 "php-fpm: pool www" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" └─97479 "php-fpm: pool www" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ... $ sudo ss -axp ... Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process u_str LISTEN 0 511 /run/php/php8.1-fpm.sock 194938 * 0 users:(("php-fpm8.1",pid=97479,fd=9),("php-fpm8.1",pid=97478,fd=9),("php-fpm8.1",pid=97477,fd=7)) u_str ESTAB 0 0 * 194937 * 194936 users:(("php-fpm8.1",pid=97477,fd=6)) u_str ESTAB 0 0 * 194936 * 194937 users:(("php-fpm8.1",pid=97477,fd=5)) ...
※ssコマンドでは、何故かcgroupを使用したフィルターが使用できなかったので、適当に表示を詰めて表示している。
続いて、いま有効になっているpreforkを無効にする。
php8.1がmpm_preforkに依存しているので、この順番で実行しないと無効にできない。
$ sudo a2dismod php8.1 $ sudo a2dismod mpm_prefork
eventとhttp2、proxy_fcgiを有効にする。
また、php8.1-fpmという設定を有効にして、php-fpmに作業を渡す方法を具体的に伝える。
$ sudo a2enmod mpm_event http2 proxy_fcgi $ sudo a2enconf php8.1-fpm $ sudo systemctl restart apache2
レスポンスを確認すると、HTTP/2になっていた。
$ curl --http2 --head http://localhost HTTP/1.1 101 Switching Protocols Upgrade: h2c Connection: Upgrade HTTP/2 200 link: <http://script.hogeserver.hogeddns.jp/wp-json/>; rel="https://api.w.org/" content-type: text/html; charset=UTF-8 date: Sun, 00 Jan 1900 00:00:00 GMT server: Apache/2.4.52 (Ubuntu)
以降、チューニングをしていく。
php.ini
php.iniは3つあった。
$ find /etc/php/8.1/ -name 'php.ini' /etc/php/8.1/fpm/php.ini /etc/php/8.1/cli/php.ini /etc/php/8.1/apache2/php.ini
コマンドラインから実行したときと、apacheから実行したときで、使うphp.iniが違うようだ。
stack overflow / 2 php.ini files
今回、apacheで直接作業をするのではなく、php-fpmに作業を渡すことにしたのだから、使われるのは/etc/php/8.1/fpm/php.iniということになる。
具体的には、apache2/php.iniとfpm/php.iniの差分を調べて、fpm/php.iniに変更点を反映させた。
変更した結果を反映させるため、必要かどうかはっきりとはわからないが、サービスを再起動しておいた。
$ sudo systemctl restart php8.1-fpm
mpm_event.conf
ApacheのMPM eventについて、/etc/apache2/mods-available/mpm_event.confで設定されている。
Apache / Apache MPM Common Directives
この他にもeventで使える設定項目はあるが、ファイルにある項目だけを整理した。
設定項目 | mpm_event.confの説明 | 設定値 | 公式サイトの説明で見つけたポイント |
---|---|---|---|
StartServers | 起動するサーバープロセスの初期数 | 2 | プロセスは負荷に応じて動的に制御されるため、通常このパラメーターを調整する理由はない。 |
MinSpareThreads | スペアを維持するワーカースレッドの最小数 | 25 | リクエスト急増への対応に利用可能なアイドルスレッドの最小値。サーバーに十分なアイドルスレッドがなければ、この数になるまで子プロセスが作られる。 |
MaxSpareThreads | スペアを維持するワーカースレッドの最大数 | 75 | サーバーのアイドルスレットが多ければ、この数より少なくなるまでプロセスが強制終了される。 |
ThreadLimit | <説明なし> | 64 | ThreadsPerChildの設定値の最大値。ThreadsPerChildの値を遥かに大きくすると、余分な未使用共有メモリが割り当てられるので注意が必要。 |
ThreadsPerChild | 各サーバープロセスにおけるワーカースレッドの数を一定にする | 25 | 子プロセスが起動時に作成するスレッドの数。 |
MaxRequestWorkers | ワーカースレッドの最大数 | 150 | 同時に処理されるリクエストの最大数。これを超えた接続は、ListenBacklogに基づく数までキューに入れられ、別のリクエストが終了するとサービスされる。 |
MaxConnectionsPerChild | サーバープロセスが処理するリクエストの最大数 | 0 | 個々のプロセスが処理するコネクション数の上限。処理が終われば子プロセスは終了する。0が設定されているときには、プロセスは終了しない。 |
自分のサイトがどの程度アクセスされているのか、1度のアクセスでどの程度の並列のリクエストがあるのか、という観点で最適値を考えることになるのだろう。
当サイトの場合、同時アクセスは殆どないに等しいので、ワーカースレッドが150もできれば十分ということで、このままで進めることにした。
仮にこれを超えた場合でも、ListenBacklog(デフォルト511)まではキューに入って順番に処理されるので、まず問題はないだろう。
php-fpm.conf
PHP FastCGI Process Managerのグローバル設定は、/etc/php/8.1/fpm/php-fpm.confにある。
ファイルの中では、設定項目についてコメントで詳しく説明がなされている。
コメントをDeepL先生に翻訳してもらった後に、公式に日本語ページがあることに気が付いたりする不思議…
PHPマニュアル / インストールと設定 / FastCGI Process Manager (FPM)
当サイトに必要な変更はないと思われた。
www.conf
PHP FastCGI Process Managerのプール設定は、/etc/php/8.1/fpm/pool.d/ディレクトリにwww.confが1つだけ設置されていた。
設定項目はたくさんあるのだけれど、今の段階で重要なのはプロセスの管理かと思ったので、それだけを抜粋した。
インストール直後は、プロセスマネージャーがdynamicに設定されており、かつ、pm.max_childrenに5が設定されている。
このpm.max_childrenの値は小さすぎて、当サイトでも足らないくらいなので、引き上げておく必要があると思われる。
実際、数値を引き上げておかないと、並列のリクエストが5つになった時点で、ログに警告が出力されたりする。
とはいえ、単純に100とか200とかにすると、プロセスが増えちゃって大変なんじゃないかと思う。
/var/log/php7.4-fpm.log
WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
さて、今回、プロセスマネージャーをstaticに変更し、あわせて、pm.max_childrenはコア数と同じ2にしみた。
[再掲]Hacker's High / php-fpm の設定を理解してサイトのパフォーマンスを向上させる
これによって並行で取り扱えるリクエストは2つになるが、プロセスを起こすオーバーヘットがないので、CPUをよりリクエストへの対応に働かせることができる。
Apacheの設定では最大150スレッドを起こすことになっているが、Apacheからの要求があふれてもlisten.backlog(デフォルト511)の分だけキューに入り、順番に処理される理屈なので問題はないだろう。
2023/06/02 追記
pmをstatic、pm.max_childrenを2にして運用をしていたら、時々ApacheもPHP-FPMもログを出さずに停止(?)していることがあった。
停止というか、アクセスするとずーっと待たされて何も表示されない、PHP-FPMを再起動すると処理が再開する、という症状だった。
Z-Pushを運用している環境で、そこからアクセスすると一発でこの状態に陥る。
想像だけれども、
PHPのプログラムから自分のサイトにWebアクセスする
ApacheがPHPの処理を要求する
PHP-FPMは処理中のために要求がキューに入る
となって、最初のPHPのプログラムはWebアクセスの応答がないので、いつまでも待っているのではないか。
PHPが自分のサイトにWebアクセスするような流れになっている場合には、それを考慮したプロセス数を設定するのだろう。
同時アクセスが多ければ多いほど、デッドロックみたいになってしまう可能性が高まるだろうから、どこかで隙間ができる程度にプロセス数を設定しておかなければ。
まっすぐ走るだけのプログラムなら、こんなことは考えなくても良いのだろうから、pm.max_childrenは2が一番効率的なんだろうけれども…仕方がない。
なお、pm.max_requestsは未設定(=0)だったものを500に設定した(500がコメントで用意されていたのでそのまま利用)。
これにより、プロセスは500回処理をすると再起動するので、アプリで何らかのメモリリークが発生していても、そのタイミングで開放されるようになる。
設定項目は後にまとめているが、この変更に関係しそうな部分だけを抜粋しておく。
設定項目 | 説明 | デフォルト値 | 設定値 |
---|---|---|---|
listen.backlog | listen(2)のバックログを設定します。 | 511 (FreeBSDとOpenBSDは-1) | なし |
pm | プロセスマネージャが子プロセスの数をどのように制御するかを選択します。 使用可能な値: static - 固定された子プロセス数(pm.max_children) dynamic - 子プロセスの数は、pm.max_children、pm.start_servers、pm.min_spare_servers、pm.max_spare_serversに基づき動的に設定されます。このプロセス管理では、常に最低1つの子プロセスが存在することになります。 ondemand - 起動時に子プロセスは作成されません。新しいリクエストが接続されると、子プロセスはフォークされます。pm.max_children、pm.process_idle_timeoutが使用されます。 備考:この値は必須です。 | なし(設定必須) | dynamic |
pm.max_children | pm が 'static' に設定されているときに作成される子プロセスの数、 pm が 'dynamic' あるいは 'ondemand' に設定されているときの子プロセスの最大数を指定します。 この値は、同時に処理されるリクエストの数の制限を設定します。mpm_prefork を使用した ApacheMaxClients ディレクティブと同等です。 オリジナルの PHP CGI の PHP_FCGI_CHILDREN 環境変数に相当します。以下のデフォルトは、あまりリソースのないサーバーを想定しています。あなたのニーズに合うように pm.* を調整することを忘れないでください。 備考:pmが「static」、「dynamic」、「ondemand」に設定されている場合に使用します。 備考:この値は必須です。 | なし(設定必須) | 5 |
pm.start_servers | 起動時に生成される子プロセスの数。 | (min_spare_servers + max_spare_servers) / 2 | 2 |
pm.min_spare_servers | アイドル状態のサーバープロセス数の最小値の希望値。 備考:pmが'dynamic'に設定されているときのみ使用されます。 備考:pmが'dynamic'に設定されている場合は必須です。 | なし | 1 |
pm.max_spare_servers | アイドル状態のサーバープロセス数の最大値の希望値。 備考:pmが'dynamic'に設定されているときのみ使用されます。 備考:pmが'dynamic'に設定されている場合は必須です。 | なし | 3 |
pm.process_idle_timeout | アイドル状態のプロセスが強制終了するまでの秒数を指定しま す。 注:pmが'ondemand'に設定されているときのみ使用されます。 | 10s | 10s |
pm.max_requests | 各子プロセスが再起動するまでに実行すべきリクエストの数です。 これは、サードパーティライブラリのメモリリークを回避するために有用です。無限にリクエストを処理したい場合は '0' を指定します。PHP_FCGI_MAX_REQUESTS と同じ意味です。 | 0 | 500 |
変更した結果を反映させるため、サービスを再起動する。
$ sudo systemctl restart php8.1-fpm
以上の設定で、だいたい問題なく動くようになったと思われる。
Ubuntu20.04でPHPを使用している環境
Ubuntu 20.04の場合も、22.04とやることは同じだった。
PHP FastCGI Process Managerをインストール。
$ sudo apt install php-fpm
php-fpmのphp.iniを設定する。
今までにファイルのアップロードサイズなどの変更を加えており、同じ動作をさせるため。
具体的には、/etc/php/7.4/apache2/php.iniと/etc/php/7.4/fpm/php.iniの差分を比較し、変更点をfpm/php.iniに反映させる。
続いて、php-fpmのpool wwwを設定する。
具体的には、プロセスマネージャーをstaticにして、pm.max_childrenをコア数に、pm.max_requestsを500に設定。
/etc/php/7.4/fpm/pool.d/www.conf
pm = static pm.max_children = 2 pm.max_requests = 500
php-fpmの設定変更を反映する。
$ sudo systemctl restart php7.4-fpm.service
続いて、Apacheを止めて、MPMをpreforkからeventに変更する。
また、関連するモジュールや設定を有効化する。
$ sudo systemctl stop apache2 $ sudo a2dismod php7.4 $ sudo a2dismod mpm_prefork $ sudo a2enmod mpm_event http2 proxy_fcgi $ sudo a2enconf php7.4-fpm $ sudo systemctl start apache2
これで、HTTP/2に切り替えることができた。
最初に設定を変更したときに、設定漏れでPHPのソースが表示されてしまった。
これは、モジュールproxy_fcgiを有効化しておらず、MPM eventが作業をリスナーに渡す事自体をしていなかったために発生していた。
もし、設定php7.4-fpmを有効にし忘れると、proxy_fcgiが作業をリスナーに渡す方法がわからないので、同様にPHPのソースが表示される。
仕組みから考えれば当然ではあるが、セットで一式ちゃんと設定することが大切。
その他
PHP-FPMとは何か
Ubuntuのマニュアルを一生懸命読んで、各設定ファイルのコメントを翻訳した後で、こういうページを見つけるわけで…
PHP / FastCGI Process Manager(FPM)
Ubuntuのマニュアルがこちらで、概要にこのようなことが書かれている。
ubuntu manuals / php-fpm - PHP FastCGI Process Manager
- デーモンとしてバックグラウンドで動作し、CGIリクエストをリスニングする。
- 出力は/var/log/php-fpm.logに記録される。
- ほとんどのオプションを/etc/php-fpm.confで設定する。
- デフォルトではlocalhost:9000/httpをリスニングして応答する。
- webserverから、".php"ファイルへの要求をすべてポート9000に転送することを期待する。
リスナーとして動作する、というのはこういうことなのかと理解。
実際にインストールすると、要求の転送はドメインソケットを通じて行われるように初期設定されている。
ポートでの転送と考えると、DockerHubにあるNextCloudのFPMは、恐らくそのタイプ。
docker-compose.ymlにNginxを加えてフロントに立たせ、NextCloudのコンテナはアプリケーションの動作だけを実行するようだった。
途中までしか試していないから断言はできないが、NextCloudコンテナのプロセス1がphp-fmpだったので、恐らくは。
Ubuntuのパッケージはこちら。
ubuntu packages / php8.1-fpm
インストール後に/lib/systemd/system/php8.1-fpm.serviceを見てみると、/etc/php/8.1/fpm/php-fpm.confを設定ファイルとして読み込むようになっていた。
php-fpm.conf
php-fpmの設定ファイルにあるコメントを、ほぼDeepL先生に翻訳してもらってみた。
最初のメッセージがこれ。
この設定ファイル内の相対パスは、すべて PHP のインストール先である /usr からの相対パスとなります。このプレフィックスは、コマンドラインから '-p' 引数を使用することで動的に変更することができます。
セクションはglobalのみ。
設定項目 | 説明 | デフォルト値 | 設定値 |
---|---|---|---|
pid | pidファイル 備考:デフォルトプレフィックスは/var。 注意事項:この値を変更した場合は、systemd service PIDFile= の設定をこの値に合わせて変更する必要があります。 | なし | /run/php/php8.1-fpm.pid |
error_log | "syslog"に設定すると、ログはローカルファイルに書き込まれるのではなく、syslogdに送信されます。 デフォルトプレフィックスは/var。 | log/php-fpm.log | /var/log/php8.1-fpm.log |
syslog.facility | syslog_facility は、メッセージをロギングするプログラムの種類を指定するために使用します。これにより、syslogd は異なる施設からのメッセージが異なるように処理されることを指定することができます。 可能な値については syslog(3) を参照してください (ex daemon equiv LOG_DAEMON) | daemon | なし |
syslog.ident | syslog_ident は、すべてのメッセージの前に付加されます。同じサーバーで複数の FPM インスタンスが動作している場合は、 一般的なニーズに合うようにデフォルト値を変更することができます。 | php-fpm | なし |
log_level | ログレベル alert, error, warning, notice, debug | notice | なし |
log_limit | 1行(ログエントリ)の文字数にログ制限をかける。制限を超えた場合は、複数行に折り返されます。この制限は、メッセージのプレフィックスとサフィックスが存在する場合、それを含むすべてのログ文字に適用されます。ただし、改行文字はファイルディスクリプタにログを記録するときのみ存在するため、この制限には含まれません。つまり、syslogにログを記録する場合、改行文字は存在しないことになります。 | 1024 | なし |
log_buffering | ログバッファリングは、ログラインがバッファリングされ、1回の書き込み操作で書き込まれるかどうかを指定します。値がfalseの場合、データはファイルディスクリプタに直接書き込まれます。このオプションは実験的なもので、重いロギングシナリオの場合、ロギングのパフォーマンスとメモリ使用量を改善できる可能性があります。このオプションは、常にバッファリングされる必要があるため、syslogにロギングする場合は無視されます。 | yes | なし |
emergency_restart_threshold | emergency_restart_interval で設定した時間内に、この数の子プロセスが SIGSEGV または SIGBUS で終了した場合、FPM は再起動します。値 '0' は 'Off' を意味します。 | 0 | なし |
emergency_restart_interval | emergency_restart_interval が、graceful restart の開始時期を決定するために使用する時間間隔。これは、アクセラレータの共有メモリの偶発的な破損を回避するために有用です。 使用可能な単位: 秒(s), 分(m), 時(h), 日(d) デフォルトの単位は秒。 | 0 | なし |
process_control_timeout | 子プロセスがマスターからのシグナルに対する反応を待つための制限時間。 使用可能な単位: 秒(s), 分(m), 時(h), 日(d) デフォルトの単位は秒。 | 0 | なし |
process.max | FPM がフォークするプロセスの最大数を指定します。これは、多くのプールで動的 PM を使用する際に、グローバルなプロセス数を制御するために設計されています。 注意深く使用してください。 値が 0 の場合は、制限なしを意味します。 | 0 | なし |
process.priority | マスタープロセスに適用するnice(2)優先度を指定する(設定されている場合のみ) 値は-19(最高優先度)から20(最低優先度)まで変化させることができます。 - FPMマスタープロセスをrootで起動した場合のみ動作します。 - プールプロセスは、特に指定がない限り、マスタープロセスの優先順位を引き継ぎます | 未設定 | なし |
daemonize | FPM をバックグラウンドに送る。デバッグのために FPM をフォアグラウンドに保つには 'no' を設定します。 | yes | なし |
rlimit_files | マスタープロセスのオープンファイルディスクリプターrlimitを設定する。 | システムの設定値 | なし |
rlimit_core | マスタープロセスの最大コアサイズrlimitを設定する。 使用可能な値: 'unlimited'、または、0以上の整数 | システムの設定値 | なし |
events.mechanism | FPMが使用するイベント機構を指定します。以下が使用可能です: - select (any POSIX os) - poll (any POSIX os) - epoll (linux >= 2.5.44) - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0) - /dev/poll (Solaris >= 7) - port (Solaris >= 10) | 未設定(自動検出) | なし |
systemd_interval | FPMをsystemdと統合して構築する場合、systemdにヘルスレポートを通知する間隔を秒単位で指定します。0を指定すると無効になります。 使用可能な単位は、s(秒)、m(分)、h(時)。 デフォルトの単位は秒。 | 10 | なし |
include | 子プロセスの複数のプールを、異なるリスニングポートや異なる管理オプションで起動することができます。プールの名前は、ログや統計情報で使用されます。FPM が扱えるプールの数には制限がありません。いずれにせよ、システムが教えてくれるでしょう 🙂 1つまたは複数のファイルをインクルードします。glob(3) が存在する場合、glob(3) パターンからファイルの束をインクルードするために使用されます。このディレクティブは、ファイル中のあらゆる場所で使用することができます。相対パスも使用可能です。これらのパスには、プレフィックスがつきます: - グローバルプレフィックスが設定されている場合 (-p 引数) は、そのプレフィックスを使用します。 - それ以外の場合は、/usr | 記載なし | /etc/php/8.1/fpm/pool.d/*.conf |
www.conf
php-fpm.confのincludeの指定によって、pool.d/www.confが読み込まれる。
この中で www というセクションが定義されていて、これがプールと呼ばれている。
こちらもほぼDeepL先生に翻訳してもらう。
インストール直後は、プロセスマネージャーがdynamicに設定されており、かつ、pm.max_childrenに5が設定されている。
これはだいぶ小さいようなので広げておいて上げるのが良さそうだ。
設定項目 | 説明 | デフォルト値 | 設定値 |
---|---|---|---|
prefix | Per pool prefix 以下のディレクティブにのみ適用されます: - 'access.log' - 'slowlog' - 'listen' (unixsocket) - 'chroot' - 'chdir' - 'php_values' - 'php_admin_values' 設定されていない場合は、グローバルプレフィックス (あるいは /usr) が代わりに適用されます。 備考: このディレクティブは、グローバルプレフィックスからの相対指定も可能です。 | なし(説明参照) | なし |
user group | Unix user/group of processes 備考:userは必須です。グループが設定されていない場合、デフォルトのユーザーのグループが使用されます。 | なし | www-data |
listen | FastCGI リクエストを受け付けるアドレスです。 有効な構文は次のとおりです: 'ip.add.re.ss:port' - TCSソケットで指定されたIPv4アドレスの指定されたポートを待ち受けます。 '[ip:6:addr:ess]:port' - TCPソケットで指定されたIPv6アドレスの指定されたポートを待ち受けます。 'port' - TCPソケットですべてのアドレス(IPv6およびIPv4-mapped)の指定されたポートの待ち受けます。 '/path/to/unix/socket' - unixソケットで待ち受けます。 備考:この値は必須です。 | なし(設定必須) | /run/php/php8.1-fpm.sock |
listen.backlog | listen(2)のバックログを設定します。 | 511 (FreeBSDとOpenBSDは-1) | なし |
listen.owner listen.group | UNIX ソケットが使用されている場合は、そのパーミッションを設定します。Linuxでは、Webサーバーからの接続を許可するために、読み取り/書き込みのパーミッションを設定する必要があります。BSD由来のシステムでは、パーミッションに関係なく接続を許可するものが多いようです。オーナーとグループは、名前または数値のIDで指定することができます。 | なし | www-data |
listen.mode | 〃 | 0660 | なし |
listen.acl_users listen.acl_groups | POSIXアクセス制御リストがサポートされている場合、これらのオプションを使用して設定することができます。 設定すると、listen.ownerとlisten.groupは無視されます。 | なし | なし |
listen.allowed_clients | 接続を許可する FastCGI クライアントのアドレス (IPv4/IPv6) のリストです。 オリジナルの PHP FCGI (5.2.2+) の FCGI_WEB_SERVER_ADDRS 環境変数に相当します。tcp リスニングソケットでのみ意味を持ちます。各アドレスはカンマで区切る必要があります。この値を空白にすると、どの IP アドレスからも接続を受け付けます。 | any | なし |
process.priority | プールプロセスに適用するnice(2)優先度を指定する(設定されている場合のみ)。 値は -19 (最高優先度) から 20 (低優先度) の間で変化します。 備考: - FPMマスタープロセスがrootとして起動されている場合のみ動作します。 - プールプロセスは、特に指定がない限り、マスタープロセスの優先順位を引き継ぎます。 | 未設定 | なし |
process.dumpable | プロセスユーザーやグループがマスタープロセスユーザーと異なる場合でも、プロセスダンプ可能フラグを設定する(PR_SET_DUMPABLE prctl)。これにより、プールユーザーのプロセスコアダンプの作成とプロセスのptraceが可能になります。 | no | なし |
pm | プロセスマネージャが子プロセスの数をどのように制御するかを選択します。 使用可能な値: static - 固定された子プロセス数(pm.max_children) dynamic - 子プロセスの数は、pm.max_children、pm.start_servers、pm.min_spare_servers、pm.max_spare_serversに基づき動的に設定されます。このプロセス管理では、常に最低1つの子プロセスが存在することになります。 ondemand - 起動時に子プロセスは作成されません。新しいリクエストが接続されると、子プロセスはフォークされます。pm.max_children、pm.process_idle_timeoutが使用されます。 備考:この値は必須です。 | なし(設定必須) | dynamic |
pm.max_children | pm が 'static' に設定されているときに作成される子プロセスの数、 pm が 'dynamic' あるいは 'ondemand' に設定されているときの子プロセスの最大数を指定します。 この値は、同時に処理されるリクエストの数の制限を設定します。mpm_prefork を使用した ApacheMaxClients ディレクティブと同等です。 オリジナルの PHP CGI の PHP_FCGI_CHILDREN 環境変数に相当します。以下のデフォルトは、あまりリソースのないサーバーを想定しています。あなたのニーズに合うように pm.* を調整することを忘れないでください。 備考:pmが「static」、「dynamic」、「ondemand」に設定されている場合に使用します。 備考:この値は必須です。 | なし(設定必須) | 5 |
pm.start_servers | 起動時に生成される子プロセスの数。 | (min_spare_servers + max_spare_servers) / 2 | 2 |
pm.min_spare_servers | アイドル状態のサーバープロセス数の最小値の希望値。 備考:pmが'dynamic'に設定されているときのみ使用されます。 備考:pmが'dynamic'に設定されている場合は必須です。 | なし | 1 |
pm.max_spare_servers | アイドル状態のサーバープロセス数の最大値の希望値。 備考:pmが'dynamic'に設定されているときのみ使用されます。 備考:pmが'dynamic'に設定されている場合は必須です。 | なし | 3 |
pm.process_idle_timeout | アイドル状態のプロセスが強制終了するまでの秒数を指定しま す。 注:pmが'ondemand'に設定されているときのみ使用されます。 | 10s | 10s |
pm.max_requests | 各子プロセスが再起動するまでに実行すべきリクエストの数です。 これは、サードパーティライブラリのメモリリークを回避するために有用です。無限にリクエストを処理したい場合は '0' を指定します。PHP_FCGI_MAX_REQUESTS と同じ意味です。 | 0 | 500 |
pm.status_path | FPM のステータスページを表示するための URI。この値が設定されていない場合、どのURIもステータスページとして認識されません。このページには、以下の情報が表示されます: pool - プールの名前 process manager - 静的、動的、またはオンデマンド start time - FPM が起動した日時 start since - FPM が起動してから何秒経ったか accepted conn - プールが受け付けたリクエストの数 listen queue - 接続待ちのキューにあるリクエストの数 (listen(2) の backlog を参照) max listen queue - FPM が起動して以来、保留中のコネクションのキューにあるリクエストの最大数 listen queue len - 接続待ちのソケットキューの大きさ idle processes - アイドル状態のプロセス数 active processes - アクティブなプロセスの数 total processes - idle + active processesの数 max active processes - FPMが起動してからの最大アクティブプロセス数 max children reached - pm がさらに子プロセスを開始しようとしたときに、プロセスの上限に達した回数 (pm 'dynamic' と 'ondemand' のみで動作する) 値はリアルタイムで更新されます。 出力例: <ここから先も長いので省略、必要時には原本のファイルを参照> | 未設定 | なし |
pm.status_listen | FastCGI ステータス要求を受け付けるアドレスです。これは、独立して要求を処理できる新しい不可視プールを作成します。これは、メインプールが長く実行されているリクエストでビジー状態になっている場合に便利です。 有効な構文は次のとおりです: 'ip.add.re.ss:port' - TCSソケットで指定されたIPv4アドレスの指定されたポートを待ち受けます。 '[ip:6:addr:ess]:port' - TCPソケットで指定されたIPv6アドレスの指定されたポートを待ち受けます。 'port' - TCPソケットですべてのアドレス(IPv6およびIPv4-mapped)の指定されたポートの待ち受けます。 デフォルト値:listenオプションの値 | listen optionの値 | なし |
ping.path | FPM の監視ページを呼び出すための ping URI。この値が設定されていない場合は、どの URI も ping ページとして認識されません。これは、FPM が生きていて応答しているかどうかを外部から調べるために使うことができます。 - FPM の可用性のグラフを作成する (rrd など) - 応答がないサーバーをグループから外す(負荷分散) - 運用チームへのアラートを発動する(24時間365日) 備考:値は、先頭のスラッシュ(/)で始まる必要があります。値は何でもかまいませんが、拡張子.phpを使用すると、実際のPHPファイルと衝突する可能性があるので、あまりお勧めできません。 | 未設定 | なし |
ping.response | このディレクティブは、pingリクエストのレスポンスをカスタマイズするために使用することができます。レスポンスは、200レスポンスコードでtext/plainとしてフォーマットされます。 | pong | なし |
access.log | アクセスログファイル | 未設定 | なし |
access.format | アクセスログフォーマット 有効な構文は次のとおりです: <ここから先は長いので省略、必要時には原本のファイルを参照> | "%R - %u %t \"%m %r\" %s" | なし |
slowlog | slow requests ログファイル(訳注:実行に時間が掛かったリクエストを記録するファイル) 備考:request_slowlog_timeoutが設定されているときは必須 | 未設定 | なし |
request_slowlog_timeout | 1つのリクエストを処理する際のタイムアウトで、その後 PHP のバックトレースが 'slowlog' ファイルにダンプされます。0s' の値は 'off' を意味します。 使用可能な単位: 秒(s), 分(m), 時(h), 日(d) | 0 | なし |
request_slowlog_trace_depth | slow log スタックトレースの階層 | 20 | なし |
request_terminate_timeout | 一つのリクエストに対応するためのタイムアウトで、その後ワーカープロセスは強制終了されます。このオプションは、iniオプションの 'max_execution_time' が何らかの理由でスクリプトの実行を停止しない場合に使用する必要があります。値 '0' は 'off' を意味します。 使用可能な単位: 秒(s), 分(m), 時(h), 日(d) | 0 | 0 |
request_terminate_timeout_track_finished | アプリケーションが 'fastcgi_finish_request' を呼び出した後や、アプリケーションが終了してシャットダウン機能を呼び出している場合(register_shutdown_function で登録)、ini オプション 'request_terminate_timeout' で設定したタイムアウトは作動しません。このような場合でも、無条件にタイムアウト制限を適用することができます。 | no | なし |
rlimit_files | ファイルディスクリプタ rlimit の設定 | システムの設定値 | なし |
rlimit_core | 最大コアサイズ rlimit の設定 使用可能な値:'unlimited'、または、0以上の整数 | システムの設定値 | なし |
chroot | 開始時にこのディレクトリにChrootします。この値は、絶対パスで定義する必要があります。この値が設定されていない場合、chroot は使用されません。 備考: '$prefix' でプレフィックスを指定すると、プールプレフィックスまたはそのサブディレクトリのいずれかに chroot することができます。 備考: chroot は素晴らしいセキュリティ機能であり、可能な限り使用すべきです。 | 未設定 | なし |
chdir | 開始時にchdirするディレクトリ 備考:相対パスを使用することも可能です。 | カレントディレクトリ chrootの時は / | なし |
catch_workers_output | Worker の stdout と stderr をメインエラーログにリダイレクトします。設定されていない場合、FastCGI仕様にしたがって、stdoutとstderrは/dev/nullにリダイレクトされます。 備考: 高負荷の環境では、ページ処理時間の遅延(数ミリ秒)を引き起こす可能性があります。 | no | なし |
decorate_workers_output | ワーカーの出力を、ログに書き込む子プロセスに関する情報を含むプレフィックスとサフィックスで装飾します。 | yes | なし |
clear_env | FPM ワーカーの環境をクリアする このプール設定で指定した環境変数が追加される前に、ワーカーの環境をクリアすることで、任意の環境変数が FPM ワーカー処理に到達するのを防止します。"no" に設定すると、すべての環境変数が PHP コードから getenv(), $_ENV, $_SERVER を通して利用できるようになります。 | yes | なし |
security.limit_extensions | FPM が解析するメインスクリプトの拡張子を制限します。これにより、Web サーバー側での設定ミスを防ぐことができます。悪意のあるユーザーが他の拡張子を使用して php コードを実行するのを防ぐために、 FPM の拡張子を .php にのみ制限する必要があります。 備考: すべての拡張子を許可するには、空の値を設定します。 | .php | なし |
env | LD_LIBRARY_PATHのような環境変数を渡します。すべての$VARIABLEは、現在の環境から取得されます。 env[HOSTNAME] = $HOSTNAME env[PATH] = /usr/local/bin:/usr/bin:/bin env[TMP] = /tmp env[TMPDIR] = /tmp env[TEMP] = /tmp | クリーンな環境 | なし |
php_value/php_flag php_admin_value/php_admin_flag | このワーカーのプールに特化した追加のphp.iniの定義です。これらの設定は、以前にphp.iniで定義された値を上書きします。ディレクティブは、PHP SAPI と同じです: php_value/php_flag - PHP の 'ini_set' から上書き可能な標準的な ini 定義を設定することができます。 php_admin_value/php_admin_flag - これらのディレクティブは、PHP の 'ini_set' コールによって上書きされることはありません。 php_*flag の場合、有効な値は on, off, 1, 0, true, false, yes または no です。 'extension' を定義すると、extension_dir から対応する共有拡張機能を読み込みます。disable_functions' または 'disable_classes' を定義すると、以前に定義した php.ini の値は上書きされず、代わりに新しい値が追加されます。 備考:パスINIオプションは相対指定が可能で、プレフィックス(pool、global、/usr)で展開されます。 php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com php_flag[display_errors] = off php_admin_value[error_log] = /var/log/fpm-php.www.log php_admin_flag[log_errors] = on php_admin_value[memory_limit] = 32M | php.iniの値、および、と起動時に -d 引数で指定する値 | なし |
WordPressのセットアップ
PHPがちゃんと動いている環境をテストのために作成。
WordPressをセットアップする。ほとんどTutorialsの手順でやっているので、手順の説明は省略。
ubuntu tutorials / Install and configure WordPress
$ sudo apt -y install apache2 ghostscript libapache2-mod-php mariadb-server php php-bcmath php-curl php-imagick php-intl php-json php-mbstring php-mysql php-xml php-zip $ sudo mkdir /srv/www $ sudo chown www-data: /srv/www/ $ curl https://wordpress.org/latest.tar.gz | sudo -u www-data tar zx -C /srv/www $ sudo tee /etc/apache2/sites-available/wordpress.conf <<EOF > /dev/null <VirtualHost *:80> DocumentRoot /srv/www/wordpress <Directory /srv/www/wordpress> Options FollowSymLinks AllowOverride Limit Options FileInfo DirectoryIndex index.php Require all granted </Directory> <Directory /srv/www/wordpress/wp-content> Options FollowSymLinks Require all granted </Directory> </VirtualHost> EOF $ sudo a2ensite wordpress $ sudo a2dissite 000-default $ sudo a2enmod rewrite $ sudo systemctl restart apache2 $ sudo mysql MariaDB [(none)]> create database wordpress; MariaDB [(none)]> create user wordpress@localhost identified by 'password'; MariaDB [(none)]> grant select,insert,update,delete,create,drop,alter on wordpress.* to wordpress@localhost; MariaDB [(none)]> flush privileges; MariaDB [(none)]> quit $ sudo -u www-data cp /srv/www/wordpress/wp-config-sample.php /srv/www/wordpress/wp-config.php $ sudo -u www-data sed -i 's/database_name_here/wordpress/' /srv/www/wordpress/wp-config.php $ sudo -u www-data sed -i 's/username_here/wordpress/' /srv/www/wordpress/wp-config.php $ sudo -u www-data sed -i 's/password_here/password/' /srv/www/wordpress/wp-config.php $ sudo sed -i "/put your unique phrase here/d" /srv/www/wordpress/wp-config.php
WordPressにアクセスし(http://<あなたのサイト>)、最終設定をすれば完了。
状態を確認、だいたいホームラボの環境と似たようなのができた。
$ php --version PHP 8.1.2-1ubuntu2.11 (cli) (built: Feb 22 2023 22:56:18) (NTS) Copyright (c) The PHP Group Zend Engine v4.1.2, Copyright (c) Zend Technologies with Zend OPcache v8.1.2-1ubuntu2.11, Copyright (c), by Zend Technologies $ apache2 -v Server version: Apache/2.4.52 (Ubuntu) Server built: 2023-03-01T22:43:55
さいごに
やりたいことがあって調べる → 現状に問題ありと気付く → 脇道に逸れて分かるまで調べる
ということで、やりたいことから少し外れたところで時間を掛けた。
弱点だなとも思っていたので、丁度いいといえば丁度いいのだが、なかなかスタートラインに立てない。
まぁでも、焦っても仕方ないか、足元から固めていこう。いつかきっと役に立つ。
コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他