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.

 

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):

PHP Benchmarks: OPcache Performance Tweaks

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

Same benchmark on 1GB/1 cpu core VPS

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:

Benchmark with PHP-FPM

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).

PHP 7 without OPcache vs PHP 7 +OPcache

References: Apache Bench, PHPPHP OPcache.
Originally published: Oct 3, 2017 | Last updated: May 12th, 2021

Tags: , ,

Discussion

  1. 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.

  2. 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?



Top ↑