A few weeks ago I wrote a short article which highlighted GUI solutions for monitoring and controlling PHP OPcache. We all know that enabling PHP OPcache provides massive performances gains (see benchmark graph at the end of article). In addition, since PHP 5.5, OPcache is now enabled by default. With these facts in mind, is it possible to squeeze a little more performance out of PHP by tweaking OPcache’s directives? This is what I’ll set out to answer.

Benchmarking PHP: Default OPcache vs OPcache + Tweaks

Today, I ran a few quick benchmarks capturing the 2nd run data of tests. First on a 32GB/16 cpu core VPS (Ubuntu 16.04 LTS), which resulted in the below PHP7 + OPcache vs PHP7 + OPcache + Tweaks benchmark graph using Apache Bench (ab):

Next, I also tested with a 1GB/1 cpu core VPS, the result:

Also, although OPcache works regardless of the PHP handler used, I wanted to make sure the results were the same with PHP-FPM as well. So I changed the default mpm_prefork to mpm_event (more about mpm_event: Strip Down Apache to Improve Performance & Memory Efficiency) and swapped out mod_PHP for PHP-FPM on the same 1GB/1 CPU core VPS:

These are not mind blowing results. However, depending on your current throughput of PHP requests, you may be happy to take whatever improvements you can find. Also, this test was with Wordpress only, with other PHP web apps and scripts these results could result in even more performance gains, or less… you can read the following config options and be the judge. Share your sweet-spot settings and/or advise for OPcache.

opcache.validate_timestamps=0

(enabled by default “1”)If enabled, OPcache will check for updated scripts every opcache.revalidate_freq=# of seconds. When disabled, opcache.revalidate_freq is ignored and you must reset OPcache manually via opcache_reset(), opcache_invalidate() or by restarting PHP for changes to the filesystem to take effect.

So by default OPcache tries to be as developer friendly as possible with time stamps to validate cached files. However, this convenience comes at the cost of performance as it does add operational overhead. For many production servers, especially when you have a separate development server, this directive can be safely disabled. If you need to keep it enabled, see the end of this post regarding increasing the time between checks from 2 seconds to maybe 10 or more depending on what you can live with.

opcache.file_update_protection=0

(default “2”) Prevents caching files that are less than this number of seconds old. It protects from caching of incompletely updated files. In case all file updates on your site are atomic, you may increase performance setting it to “0”. Documentation is limited.

opcache.fast_shutdown=1

Fast shutdown attempts to use a faster mechanism for clearing memory. If enabled, a fast shutdown sequence is used that doesn’t free each allocated block, but instead relies on the Zend Engine memory manager to deallocate the entire set of request variables in mass. Use this with PHP7+, may experience segfaults with older versions of PHP.

Here’s a copy of the config (opcache.ini) that was used…

default PHP OPcache:

zend_extension=opcache.so

PHP OPcache + tweaks:

zend_extension=opcache.so opcache.fast_shutdown=1 opcache.file_update_protection=0 opcache.validate_timestamps=0 opcache.interned_strings_buffer=16

Example command:

ab -n 1000 -c 20 -g opcache_yes.dat http://localhost/ This is ApacheBench, Version 2.3 <$Revision: 1706008 $> 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) Completed 100 requests Completed 200 requests Completed 300 requests Completed 400 requests Completed 500 requests Completed 600 requests Completed 700 requests Completed 800 requests Completed 900 requests Completed 1000 requests Finished 1000 requests Server Software: Apache/2.4.18 Server Hostname: localhost Server Port: 80 Document Path: / Document Length: 51919 bytes Concurrency Level: 20 Time taken for tests: 1.815 seconds Complete requests: 1000 Failed requests: 0 Total transferred: 52154000 bytes HTML transferred: 51919000 bytes Requests per second: 551.08 [#/sec] (mean) Time per request: 36.292 [ms] (mean) Time per request: 1.815 [ms] (mean, across all concurrent requests) Transfer rate: 28067.40 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.1 0 0 Processing: 19 36 5.6 35 66 Waiting: 17 33 5.4 33 62 Total: 19 36 5.6 35 66 Percentage of the requests served within a certain time (ms) 50% 35 66% 37 75% 39 80% 40 90% 43 95% 46 98% 51 99% 53 100% 66 (longest request)

If you are wondering why all the fuss about PHP Opcache, here’s a benchmark of PHP 7 without OPcache vs PHP 7 +OPcache (concurrency lowered to 2 because without opcache PHP fails 90% of requests).

References: Apache Bench, PHP, PHP OPcache.