phpのマルチスレッド化とはなんなのか(未解決)

  • このエントリーをはてなブックマークに追加

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で動くようになってしまいました。なんだかよくわかりませんでした(未解決)