If you’re using automated deployments on a regular base, chances are that you are using symlinks to limit the amount of downtime to a minimum. This is a proven approach that has worked well for many years.
website current -> releases/release-12 releases/release-11 releases/release-12
When time has come to deploy a new release, the release is prepared in releases/release-13. Once all preparations are done, the current symlink is updated to point to release-13 and the new version of the site is online instantaniously.
When it comes to opcode caching, the old APC would simply monitor the file timestamp for changes. It did not resolve the symlink and would check the timestamp through the symlink. When the symlink was updated, APC would check the timestamp of the file in the new location.
OPCache on the other hand is aware of the symlink and will resolve the symlink to the actual location of the file. When the symlink changes to a new version, OPCache will still be checking the file in the old release folder. As that file didn’t change, the cache will not be invalidated and the website would still be serving of the old release.
To overcome this problem, you will need to clear OPCache. This can be done in serveral ways, depending on how you are running your PHP process.
One of the easiest ways for developers to reset the opcache, is by calling the PHP opcache_reset() function. A simple file with nothing else in it should do the trick in most cases:
The key here is to run this function in the same way as the opcache you are trying to reset. As the opcache is bound to the running process, calling opcache_reset from the CLI will not clear the OPCache from your webserver. This means that you probably need to use curl or wget in your deployment process to clear the cache. Note that when running your PHP through (fast)cgi, this might not be a good option.
If opcache_reset would not be an option, you still have alternative options to clear the OPCache
If you’re running PHP through Apache’s mod_php, you need to reload or restart Apache. This will stop the old process and spawn a new one, resulting in an empty OPCache.
service apache2 reload -or- service apache2 restart
If you’re using FastCGI to run your PHP, your PHP processes will probably automatically be recycled every X requests to prevent memory leaks. Depending on how high your X is and how much traffic the site gets, this could take anywhere from a few seconds to infinity before the process is recycled.
Also note that each FastCGI worker process will have its own OPCache. Using the opcache_reset() function will not clear the OPCache of all processes, just the process that handles the request. To force reload the processes, you typically need to restart your webserver or kill all the worker processes.
The nice part about PHP-FPM is that OPCache is stored in the master process, not in the workers. If one worker clears OPCache using opcache_reset(), it is cleared for all workers. The drawback is that if you are running a single master process with multiple pools, the opcache of all pools would be cleared, not just the pool that made the call. To overcome this, you can run each pool off its own master process.
Another way to clear the cache, is to simply restart the master process. This will clear the OPCache of all pools running off this master process.
Alternatively, you can also look into tools like cachetool that can directly connect to the PHP-FPM socket to clear the cache.
When using symlinks in your deployment setup, you will need to trigger a clear of the OPCache after you have updated the symlink. The options vary depending on how you are running your PHP. If possible, try choosing an option that does not involve hard restarting any services, as these might result in temporary failures of your website.
Hi there! My name is Tom. I’m a Linux System Administrator and PHP Developer. My job is to keep PHP websites running as smooth as possible. Being both on the ‘dev’ and ‘ops’ side gives me a broad skillset across the entire stack.