Information

This article was written on 03 Oct 2015, and is filed under Technical.

Deploying via a symlink and optimising OPcache

This is a very technical post. It’s about the way we are deploying new versions of the Alpine Booking system to the thirty clubs that are currently using the system. Previously, each club had a copy of the source code in the webroot for their domain. These were deployed using rsync – the steps were as follows:

  1. Use git to pull the source code and static assets from the cloud (github.com in our case).
  2. rsync to one or to all clubs

With PHP 5.5, OPcache became part of the default configuration.  This caches compiled code, improving performance across the server.  However with 30 instances of the alpine booking system (and another 30 for the mobile web-app), this was inefficient for us, using a lot of memory for a diluted effect.  So we have now taken advantage of the fact that OPcache works from the “realpath”, i.e. from the fully resolved filename, after traversing any symlinks.

To do this, we got rid of the source code in apache’s webroot, replacing it with a symlink for each club (instance). So the webroot is more-or-less empty.  When our deploy script pulls a deploy tag from github.com, it copies the source code into a release directory.  It then updates the symlink for one or for all clubs to point to this release directory.  Because OPcache works on the fully resolved name of each requested file, it will cache each file only once, even though several instances are using it.

As I’ve hinted above, our deploy script can either deploy to a single instance (club) or to all of them. In the latter case, all release directories other than the new one are deleted. When upgrading all instances to a new release in this way, our deploy script instructs apache to reload its config, which restarts the OPcache.

As the number of clubs using the system continues to grow, this deployment method should help to keep the webserver fast and efficient.

We are interested to know what people think of this solution.  What other solutions are in use? Can you see any pitfalls in our solution?