どうも、やまもとやまです。
最近はpythonやjsの利用が増えてきているとはいえ、WordPressを中心にまだまだ広く利用されているPHP。
WebサイトでPHPを利用する場合、モジュール版やCGI版、FastCGI、FPM(これもFastCGIですが)と複数の実行形式がありますよね。
何となく、モジュール版は速くてCGIは遅い、FastCGIはそこそこ速くてFPMもそこそこ速い、という印象がありますが、実際のところどうなのでしょうか。
気になる気になる。そうだ、比較してみよう。
環境
ベンチマークをとった環境は以下のものです。
物理ハードウェア
CPU:Intel(R) Xeon(R) Silver 4309Y CPU @ 2.80GHz x2
HDD:SAS RAID10
対象の物理ハードウェア上に、KVMで仮想マシンを作成し、仮想マシンでPHP処理をさせた場合のベンチマークを実施しました。
※PHP処理としては、WordPressトップページへのアクセスとなり、Apache Benchでベンチマークをとります
仮想マシンスペックは、4コア、メモリ4GBとなります。
OSはAlmaLinux8、PHPはAppStreamの7.4を利用します。
比較対象
以下の3種類のPHP実行について比較を行います。
- Apache + mod_php
- Apache + FastCGI(mod_fcgid)
- Apache + php-fpm
mod_phpはスレッドセーフでないため、1についてはMPMはpreforkで、2と3はeventを使用します。
ApacheおよびPHPの各設定は大まかにあわせるため、こんな感じにしておきました。
※各方式で、100同時実行が可能な設定になっています
もし比較条件がおかしい等があればご指摘ください。
○Apache MPM設定
StartServers 100
MinSpareServers 100
MaxSpareServers 100
ServerLimit 100
MaxClients 100
MaxRequestsPerChild 500
</IfModule>
<IfModule mpm_event_module>
AsyncRequestWorkerFactor 2
ServerLimit 10
ThreadLimit 200
ThreadsPerChild 200
MaxRequestWorkers 2000
MinSpareThreads 2000
MaxSpareThreads 2000
MaxConnectionsPerChild 500
</IfModule>
○fcgid設定
FcgidMaxProcessesPerClass 100
PHP_FCGI_MAX_REQUESTS 500
○php-fpm設定
pm.max_children = 100
pm.max_requests = 500
それぞれでphpinfoを表示して、想定通りの実行形式になっていることを確認しておきましょう。
想定通りになっていますね。
ベンチマーク方法
Apache Benchでベンチマークをとります。
オプションとしては、cで同時接続数、nでリクエスト数を指定し、パフォーマンスを計測します。
例として、10同時接続で100リクエストを処理させてみましょう。
$ ab -c 10 -n 100 http://198.51.100.50/
(前略)
Server Software: Apache
Server Hostname: 198.51.100.50
Server Port: 80
Document Path: /
Document Length: 52884 bytes
Concurrency Level: 10
Time taken for tests: 1.667 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Total transferred: 5309200 bytes
HTML transferred: 5288400 bytes
Requests per second: 59.97 [#/sec] (mean)
Time per request: 166.745 [ms] (mean)
Time per request: 16.675 [ms] (mean, across all concurrent requests)
Transfer rate: 3109.39 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 1
Processing: 47 121 61.5 105 470
Waiting: 44 116 61.1 100 468
Total: 47 121 61.5 105 470
Percentage of the requests served within a certain time (ms)
50% 105
66% 128
75% 158
80% 171
90% 193
95% 221
98% 250
99% 470
100% 470 (longest request)
この例では、100リクエストを約1.667秒ですべて実行完了し、秒間約60リクエストを処理できています。
また、100リクエスト実行したうちの失敗やエラーはなく、すべて正常に実行完了しています。
比較してみる
では比較していきます。
リクエスト数 n は1000とし、同時接続数を変更しながら実行してみました。
結果は以下の表の通りです。
1.mod_php
同時接続数 | 秒間リクエスト数 | エラー |
10 | 97.26 | 0 |
30 | 100.61 | 0 |
50 | 100.37 | 0 |
100 | 99.46 | 0 |
150 | 97.76 | 0 |
200 | 99.36 | 0 |
250 | 98.64 | 0 |
300 | 98.46 | 0 |
400 | 71.24 | 0 |
500 | 71.11 | 0 |
2.FastCGI(fcgid)
同時接続数 | 秒間リクエスト数 | エラー |
10 | 95.31 | 0 |
30 | 93.10 | 0 |
50 | 91.38 | 0 |
100 | 88.60 | 0 |
150 | 87.59 | 0 |
200 | 87.72 | 0 |
250 | 86.84 | 0 |
300 | 87.64 | 0 |
400 | 87.54 | 0 |
500 | 86.67 | 0 |
3.php-fpm
同時接続数 | 秒間リクエスト数 | エラー |
10 | 98.14 | 0 |
30 | 100.41 | 0 |
50 | 99.71 | 0 |
100 | 100.20 | 0 |
150 | 100.62 | 0 |
200 | 100.63 | 0 |
250 | 100.04 | 0 |
300 | 99.92 | 0 |
400 | 100.71 | 0 |
500 | 100.67 | 0 |
同時接続が少ないときはあまり差がないですが、FastCGIが若干パフォーマンスが低いようです。
また、mod_phpは同時接続が300を超えたあたりから急激にパフォーマンスが落ちています。
今回の条件下では、php-fpmに関しては想像していた以上にパフォーマンスが高く、劣化もしないようでした。
※物理ハードウェア自体の性能、Apache/PHP設定、処理するPHPの内容、Apache Bench側のオプション等、設定する条件により、ベンチマーク結果も変わってくると思います
なお、FastCGIについては仕組み上、初回実行時はパフォーマンスが上記結果よりも低くなります。
結果として・・・
予想としてはパフォーマンスではmod_phpが有利かと思っていましたが、php-fpmが想像以上に優秀な結果となりました。
また、設定を変えつつ試してみたところ、mod_phpでは同時接続数がMaxClientsより大幅に増えるとパフォーマンスが劣化するようです。
MaxClientsを増やしていくとどうしても全体の使用メモリが増えるということもあり、総合的にもevent MPM+php-fpmが有利になりそうですね。
それではまた!