Apache + PHP-FPMでThread Safetyがdisabledとなる
Apache + mod_phpはpreforkで動かす必要があると言われます。
preforkは子プロセスをforkして並べる方式で、起動した子プロセスの数 = 接続数の上限となるので、大量のアクセスをさばきたい場合は子プロセスを大量にforkする必要があり、メモリ効率が悪いし、子プロセスforkのオーバーヘッドが大きいです。
Apacheをworkerもしくはeventにするとやはりプロセスをforkして並べるものの、1つの子プロセスごとにマルチスレッドで複数の通信をさばけるので、メモリ使用率を抑えることができると言われます。
しかし、PHPの公式サイトには
http://jp2.php.net/manual/ja/faq.installation.php#faq.installation.apache2
マルチスレッド MPM を使いたい場合は、 PHP が自分のメモリ空間で実行される FastCGI の設定をみてください。
とあり、mod_phpはマルチスレッドに対応していないので、worker/eventにしたい場合は、FastCGIを使えとのことです。
なるほどとおもって実際にAmazonLinuxでApache2.4 + worker/event とphp71-fpmで動かしてphpinfoを表示すると、
Thread Safety disabled
と表示されます。 これはスレッドセーフではない(マルチスレッドで動いてない)という意味に取れます。
これでいいのかな?
mod_phpでworker設定ができてしまう
調べてみると、PHPの動作には、ZTS((Zend Thread Safe)とNTS(Non Thread Safe)があり、ZTSだとスレッドセーフであり、マルチスレッドで動作可能なようです。
参考:動作中のPHPがZTSかNTSか判定する方法
https://qiita.com/hnw/items/de83634fe39574b76ba1
AmazonLinuxでphp71-cliをインストールすると、/ust/bin/php
と、/usr/bin/zts-php
が入り、
# /usr/bin/php -i | grep Thread
Thread Safety => disabled
# /usr/bin/zts-php -i | grep Thread
Thread Safety => enabled
となります。
zts-phpはスレッドセーフなphpのようです。
そして
# ls -l /etc | grep php
drwxr-xr-x 2 root root 4096 Dec 11 04:40 php-7.1.conf
drwxr-xr-x 2 root root 4096 Dec 11 04:54 php-7.1.d
-rw-r--r-- 1 root root 62436 Dec 11 04:41 php-7.1.ini
drwxr-xr-x 2 root root 4096 Dec 11 04:44 php-zts-7.1.d
lrwxrwxrwx 1 root root 27 Dec 11 04:42 php-zts.d -> /etc/alternatives/php-zts.d
lrwxrwxrwx 1 root root 23 Dec 11 04:42 php.d -> /etc/alternatives/php.d
lrwxrwxrwx 1 root root 25 Dec 11 04:42 php.ini -> /etc/alternatives/php.ini
このディレクトリ構成はほんと頭がこんがらがる(実際に公式の中の人もtypoしてる)のでほんとにやめてほしいのですが、
# zts-php -i | grep 'Scan this dir for additional .ini files'
Scan this dir for additional .ini files => /etc/php-zts-7.1.d
# php -i | grep 'Scan this dir for additional .ini files'
Scan this dir for additional .ini files => /etc/php-7.1.d
のように、ZTS版とNTS版とでは別のiniファイル格納ディレクトリを見に行っています。
どうやら、AmazonLinuxのPHPのCLI版では、デフォルトではNTS版が使われるが、ZTS版も一緒に入っており、PHPモジュールもNTS版、ZTS版両方の設定ファイルも用意されているので、どちらも利用可能な状態、ということがわかりました。
また、yumでmod_phpを入れるため、php71をインストールすると、
# ls -l /etc/httpd/modules/ | grep php
-rwxr-xr-x 1 root root 4268008 Dec 5 19:41 libphp-7.1.so
-rwxr-xr-x 1 root root 4467536 Dec 5 19:41 libphp-zts-7.1.so
lrwxrwxrwx 1 root root 31 Dec 11 04:42 libphp-zts.so -> /etc/alternatives/libphp-zts.so
lrwxrwxrwx 1 root root 27 Dec 11 04:42 libphp.so -> /etc/alternatives/libphp.so
のように、mod_phpも、ZTS版と思われるものと、NTS版の両方が入っています。
そして、
# cat /etc/httpd/conf.modules.d/15-php.conf
#
# PHP is an HTML-embedded scripting language which attempts to make it
# easy for developers to write dynamically generated webpages.
#
# Cannot load both php5 and php7 modules
<IfModule !mod_php5.c>
<IfModule prefork.c>
LoadModule php7_module modules/libphp-7.1.so
</IfModule>
</IfModule>
<IfModule !mod_php5.c>
<IfModule !prefork.c>
LoadModule php7_module modules/libphp-zts-7.1.so
</IfModule>
</IfModule>
で、preforkの設定にするとlibphp
が使用され、それ以外(worker/event)の設定にすると、libphp-zts
といういかにもZTSっぽい方のmod_php
が使用されるよう定義されていることが分かります。
mpmの変更は
/etc/httpd/conf.modules.d/00-mpm.conf
LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
とデフォルトではpreforkとなっているので、
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
LoadModule mpm_worker_module modules/mod_mpm_worker.so
としてApacheをrestartして、
ドキュメントルートにinfo.php
<?php phpinfo();
を作成してブラウザでアクセスすると、Thread Safetyがenabledになりました。
???
公式ではmod_phpはpreforkで動かせと書いてあるのに、普通にworkerで動くようになってしまいました。なんだかよくわかりませんでした(未解決)