Now that you've optimized PHP realpath_cache_size, it's time to fine-tune PHP OPcache. With just a few tweaks you can tune OPcache to make it perform much better, and here is how! ...

In this article shows you'll learn how to optimize PHP's OPcache configuration and make OPcache perform even better. After configuring and optimizing PHP realpath_cache_size, the OPcache cache mechanism is the next step to fine-tune. With just a few tweaks you can tune OPcache to make it perform much better, and here is how!

So let's start to optimize PHP's OPcache configuration and make OPcache perform even better!

PHP OPcache opcode cache

PHP OPcache is an opcode cache: OPcache improves PHP performance by storing precompiled script byte-code in shared memory, thereby removing the need for PHP to load and parse scripts on every request. This allows PHP to use the precompiled byte-code instead of compiling it on every request.

The OPcache extension is bundled with PHP 5.5.0 and later.

Wondering how to flush OPcache in WordPess?

OPcache default configuration

OPcache comes with a default configuration that can work perfectly in your environment. Use the opcache_get_status() function to get the current status information about the cache. This information is valuable for further optimizing your OPcache configuration and thus your PHP and website performance.

Some of the default OPcache configuration settings are:

; The OPcache shared memory storage size.
;opcache.memory_consumption=64
; The amount of memory for interned strings in Mbytes.
;opcache.interned_strings_buffer=4
; The maximum number of keys (scripts) in the OPcache hash table.
; Only numbers between 200 and 100000 are allowed.
;opcache.max_accelerated_files=2000
; If enabled, a fast shutdown sequence is used for the accelerated code
;opcache.fast_shutdown=0

They're commented out since they're default.

Fine-tune default PHP OPcache configuration

You can fine-tune PHP's OPcache configuration by utilizing the opcache_get_status() function. One piece of information it provides is current memory_usage:

[memory_usage] => Array
  (
      [used_memory] => 41594440
      [free_memory] => 21280800
      [wasted_memory] => 4233624
      [current_wasted_percentage] => 6.3085913658142
  )

Values are in bytes, which makes the OPcache shared memory storage size 64 MB ((41594440 + 21280800 + 4233624) / 1048576).

Don't forget, this 64 MB is for every website (in IIS terms: application pool or worker process). This means that 64 MB per website becomes 6400 MB - or 6,4 GB - for one hundred websites on your server. You need to have that available.

These numbers show me that I, in this particular situation, don't need 64 MB shared memory storage. Trust me, the application runs for quite a while with this config so the numbers are valid, so to speak. Therefore, I can decrease the opcache.memory_consumption setting to some 42+ MB. Let's say 48 MB to have something to spare:

opcache.memory_consumption=48

If necessary you can also increase OPCache's memory limit (opcache.memory_consumptions)

; default = opcache.memory_consumption=128
opcache.memory_consumption=150

The opcache.interned_strings_buffer setting is an important one. String interning is a method of storing only one copy of each distinct string value, which must be immutable. For example, if I have the string "The quick brown fox jumps over the lazy dog" a hundred (100) times in my code, PHP will store 1 variable in memory. The 99 other times, a memory pointer is used to refer to this string.

I believe this happens a lot when you code, so in my opinion this setting may be increased:

; default = opcache.interned_strings_buffer=8
opcache.interned_strings_buffer=16

opcache.max_accelerated_files configures the number of files to be held in memory. A vanilla WordPress website consists of more than 2000 files, not to mention Prestashop, Joomla, Drupal or Magento. Increase this one as high as you think is necessary (and as long as you have physical and virtual memory to spare):

opcache.max_accelerated_files=5000

Another interesting setting is opcache.fast_shutdown. What this actually does is provide a faster mechanism for calling the deconstructors in your code at the end of a single request to speed up the response and recycle php workers so they're ready for the next incoming request faster.

A fast shutdown sequence relies on the Zend Engine memory manager to deallocate the entire set of request variables en masse. Turn it on: opcache.fast_shutdown=1

Warning: Changing this option is known to cause segfaults under yet to be determined conditions. See the issue #146 on the Opcache repository for more information. We have therefore removed this as a hint.

Fine-Tune Your Opcache Configuration to Avoid Caching Suprises - Tideways

Please note that opcache.fast_shutdown is removed in PHP 7.2.0.

Other valuable OPcache settings

Other settings to look at, but are not described in this article, are: opcache.validate_timestamps and opcache.revalidate_freq. Read the docs to determine how to configure these for yourself.

Set opcache.error_log=/path/to/your/logfile and opcache.log_verbosity_level=3 or 4 (info messages or debug messages) to temporarily enable OPcache logging. The logfile must be writable by the web server process. But be careful with these settings.

OPcache security

It's important to go over all OPcache configuration settings. Leaving one untouched, or setting it incorrectly, may open up your server for a new range of attack vectors. A binary webshell through OPcache in PHP 7 is one of them.

Check out Mattias Geniar's post Mitigating PHP’s long standing issue with OPCache leaking sensitive data and explicity enable the following two settings:

; Validate cached file permissions.
opcache.validate_permission=1

; Prevent name collisions in chroot'ed environment.
opcache.validate_root=1

Conclusion PHP OPcache optimization

Tuning OPcache configuration and runtime settings decreases CPU usage on your web server, and may increase memory usage. If done right this'll speed up your - or your customer's - websites and PHP throughput.

After making the changes above, and letting Saotn.org run for a little while (little being the operative word...), the OPcache numbers are:

Array
(
    [opcache_enabled] => 1
    [cache_full] => 
    [restart_pending] => 
    [restart_in_progress] => 
    [memory_usage] => Array
        (
            [used_memory] => 33098648
            [free_memory] => 17233000
            [wasted_memory] => 0
            [current_wasted_percentage] => 0
        )

    [interned_strings_usage] => Array
        (
            [buffer_size] => 8388608
            [used_memory] => 4773248
            [free_memory] => 3615360
            [number_of_strings] => 72659
        )

    [opcache_statistics] => Array
        (
            [num_cached_scripts] => 801
            [num_cached_keys] => 1529
            [max_cached_keys] => 7963
            [hits] => 947
            [start_time] => 1438332765
            [last_restart_time] => 0
            [oom_restarts] => 0
            [hash_restarts] => 0
            [manual_restarts] => 0
            [misses] => 801
            [blacklist_misses] => 0
            [blacklist_miss_ratio] => 0
            [opcache_hit_rate] => 54.176201372998
        )

On a side note: my website also runs ran WinCache Extension for PHP, as caching back-end in PHP, so these numbers might not reflect your situation. Always test configuration settings in your test- or staging environment before putting it into production.

Donate a cup of coffee
Donate a cup of coffee

Thank you very much! <3 ❤️

5 Comments

  1. Miko

    Hi Luke, the `opcache.fast_shutdown` setting is removed since PHP 7.2. It is now automatically used if possible.

  2. Do you know if they have fixed the WordPress update / clear OpCache bug? I noticed it had been punted some >5.0 but nothing after that.

    I installed your OpCache clearing code in the mu-plugins directory but I do not get any indication that it even exists. I don’t have any updates right now. Should there be any sign it is installed?

    Last, if opcache.validate_timestamps is turned on, other than a validation time delay in opcache.revalidate_freq, is the clearing option needed?

    • Hi Bill, thank you for your comment.

      I don’t think the WordPress folks fixed the issue with updates when opcache.validate_timestamps is disabled. Setting `opcache.validate_timestamps=1` may cause a performance degradation, since PHP checks the file timestamp on every request (if `opcache.revalidate_freq` is set to 0). If you leave opcache.revalidate_freq at it’s default of 2 seconds, you may run into issues when WordPress updates a file, and refreshes the page within those 2 seconds.

      I’d say: test and go with what’s best in your situation, because my plugin bluntly flushes all OPcache cache.

      About the plugin, you’ll find it listed as a Must-Use plugin:

      WordPress Must-use plugins screenshot

  3. Luke Cavanagh

    Awesome post, thank you for sharing!

Comments are closed