PHP Benchmarks: OPcache vs OPcache w/ Performance Tweaks
A few weeks ago, I wrote a short article highlighting GUI solutions for monitoring and controlling PHP OPcache. We all know that enabling PHP OPcache provides massive performance gains (see benchmark graph at the end of the 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.
Table of Contents
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, and the result:
Also, although OPcache works regardless of the PHP handler used, I wanted to ensure the results were the same with PHP-FPM. 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 advice 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 timestamps 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. You may increase performance by setting this to “0”. Documentation is limited.
opcache.fast_shutdown=1
Fast shutdown attempts to use a faster mechanism for clearing memory. If enabled, an immediate shutdown sequence is used that doesn’t free each allocated block. Instead, it relies on the Zend Engine memory manager to deallocate the entire set of request variables in mass. Use this with PHP7+. You may experience segfaults with older versions of PHP.
PHP 8 Performance Tips.
Also, see PHP 8 Compatibility Check and Performance Tips.
Here’s a copy of the config (opcache.ini) that I’ve 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.
Originally published: Oct 3, 2017 | Last updated: April 15th, 2024
Thanks, I’ll try these out to see if my cache hit rate improves.
I’ve also seen a few sources up the interned_strings_buffer as well, but what exactly does this do? I’m normally hesitant to mess with defaults unless I am sure.
Opcache has been great ever since its introduction and really helps with all of my websites.
Having said that, I’m still uncertain on the best value for validate_timestamps. If there was a way to easily check for when a file was updated to restart PHP, I’d set to 0. Is there a way to do that?