PHPコードキャッシュにOPcacheを使ってみる | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

コードキャッシュといえばAPC だったんですけど、どうも最近開発がされていないっぽいので代用を探していたんですが、PHP5.5.0以上であればOPcache がデフォルトでバンドルされているのでこれを使ってみたいと思います。



OPcacheをインストールする


今回の環境では、PHP5.6.8/CentOS6.6にてOPcacheを使ってみます。

PHP5.4以前のバージョンではPECL経由でインストールできるみたいですが、詳細はマニュアル を参照してみてください。

インストールはPHPをコンパイルする際に--enable-opcacheオプションを付けるだけで利用できるようになります。


$ ./configure --enable-opache
-- その他のオプション --

make、make installまで完了するとopcache.soファイルが作成されるのでパスを確認しておきます。

例えば、下記のようなパスに作成されます。


/path/to/php/extensions/no-debug-non-zts-20131226/opcache.so

あとは、php.iniを編集してOPcacheをロード、有効化すれば使えます。


[opcache]
zend_extension=/path/to/php/extensions/no-debug-non-zts-20131226/opcache.so
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.enable_cli=1

ちなみに、マニュアル上ではXdebugと同時に使っている場合は、(理由はよくわかりませんけど)OPcacheのほうを先にロードしろとあるので、この設定はXdebugの設定より設定ファイル上先に書いておいたほうが良さそうです。


この設定は、マニュアル上で推奨している値そのままです。

その他にも幾つも設定項目があるので、詳細は実行時設定のマニュアル を参照。

opcache.save_commentsとか有効にしたほうが良さそうなのにコメントに依存するアプリケーションを破壊するかもしれないとか怖いこと書いていて、実際にそんなことしているソースあるんだとか思ったり(独り言)。


まぁ、設定変更するとしてもOPcacheが使うメモリ量(opcache.memory_consumption)やファイルのタイムスタンプを確認する頻度(opcache.revalidate_freq)を変えるぐらいでしょうか。

opcache.revalidate_freqに関しては、プログラムをリリースしても反映までにこの秒数またされるっぽいので、OPcacheが原因でプログラムが即時に反映されないといった記事をよくみます。

また、キャッシュをさせたくない場合は、opcache.enable=0にすればすぐに無効化されます(要Apache再起動)。


CLI上でもOPcacheを有効にしている関係で、下記のように利用できるかどうか簡単に確認できます。


# php - v
PHP 5.6.8 (cli) (built: Jun 10 2015 09:50:05) 
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies
    with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2015, by Zend Technologies
    with Xdebug v2.3.2, Copyright (c) 2002-2015, by Derick Rethans

もちろんphpinfo()からでも。


ZendOPcache-1



OPcacheのキャッシュ状況を確認する


APCの場合、キャッシュ状況やメモリ使用量などをグラフ化してくれるプログラムが付属していますがOPcacheではありません。

ただ、GitHub上にそれっぽいことをしてくれるソースが公開されています。


https://gist.github.com/ck-on/4959032


このプログラムを適当な場所に設置してアクセスしてみるとOPcacheのキャッシュやメモリ使用状況が確認できます。


ZendOPcache-2


で、実際のところの効果はということでLaravelのプログラムに対してApacheBenchでアクセスしてテストしてみます。

まずは、OPcacheを無効にした場合


$ ab -n 100 -c 100 http://localhost/foo
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient).....done

Server Software:        Apache/2.2.15
Server Hostname:        localhost
Server Port:            80

Document Path:          /foo
Document Length:        2617 bytes

Concurrency Level:      100
Time taken for tests:   11.095 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      288300 bytes
HTML transferred:       261700 bytes
Requests per second:    9.01 [#/sec] (mean)
Time per request:       11095.334 [ms] (mean)
Time per request:       110.953 [ms] (mean, across all concurrent requests)
Transfer rate:          25.37 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        4   24   5.5     24      49
Processing:   904 7264 3788.2   8550   11062
Waiting:      896 7252 3783.8   8472   11061
Total:        924 7288 3789.9   8574   11091

次に、OPcacheを有効にした場合


$ ab -n 100 -c 100 http://localhost/foo
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient).....done

Server Software:        Apache/2.2.15
Server Hostname:        localhost
Server Port:            80

Document Path:          /foo
Document Length:        2617 bytes

Concurrency Level:      100
Time taken for tests:   4.670 seconds
Complete requests:      100
Failed requests:        2
   (Connect: 0, Receive: 0, Length: 2, Exceptions: 0)
Write errors:           0
Total transferred:      282534 bytes
HTML transferred:       256466 bytes
Requests per second:    21.41 [#/sec] (mean)
Time per request:       4670.117 [ms] (mean)
Time per request:       46.701 [ms] (mean, across all concurrent requests)
Transfer rate:          59.08 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        3   24   3.4     25      25
Processing:   879 2815 1274.5   2877    4643
Waiting:        0 2791 1306.5   2871    4643
Total:        902 2838 1275.4   2902    4667

結果を見るとRequests per secondが9.01に対して有効にした場合は21.41に、Time per request(mean, across all concurrent requests)が、110.953に対して有効にした場合は46.701となっているので、大体倍ぐらいの性能は出るようになったっぽいです。


フレームワークとか多数のライブラリが読み込まれる場合は結構有効に働いてくれる気がします。

もちろん、より多くのメモリを食ったりキャッシュが利いてプログラムが更新されないといった弊害もあったりしますのでチューニングは必要になってくるかと思います。

でも、デフォルトでバンドルされているものなので使わない手は無いと思いますが。