GPUonCLOUD - ZDT for PHP
The majority of modern web-services should be accessible for users at all times. A common but often overlooked problem here is the process of project re-deployment (i.e. update), causing your application to go down or return errors until the operation is finished. This can be solved with a variety of tools like Capistrano, Fabric and others. However, these supplements often require additional time, expense, and specialist knowledge for being successfully integrated and configured properly (e.g. this may be performed through setting up multiple servers with a load-balancer in front of them; while the deployment is running on one server - it is excluded from the route list, after that other servers could be updated). Obviously, such an implementation is rather complicated and requires a lot of extra resources, thus a better method is needed.
Such a new solution was proposed for PHP applications, running on top of Apache, by founder of this programming language and, simultaneously, GPUonCLOUD technical advisor - Rasmus Lerdorf. As an actively used at Etsy, and, therefore, being a battle-tested approach, it was subsequently taken as the basis for Zero Downtime & Atomic Deployment feature in GPUonCLOUD. The main idea of this method rests on the following two points:
each time a new deployment process is run, the corresponding app’s files are duplicated, being stored in a separate server directory (which is automatically named according to its creation date/time for easy identification)
In such a way, the updated project files can be seamlessly deployed, while the initial code version continues working and handling users’ sessions. And when the deployment is fully completed, the symlink instantly switches to the most recent version of the successfully deployed app, starting to redirect all the incoming requests to it. All of these together makes the deployment process fully atomic and implicit for your customers, simultaneously relieving you from performing plenty of envisioned manual operations.
ZDT deployment workflow
how ZDT functionality is ensured at GPUonCLOUD
atomic and classic deployment modes comparison
So, let’s go on!
ZDT Deployment Workflow
First of all, we’ll consider more specifically how the above described PHP zero-downtime deployment mechanism actually works onGPUonCLOUD - let’s examine all of these processes step-by-step with a real example.
1. To start with, you’ll need a PHP environment (either a new or the already existing one)
2. Next, proceed to the deployment of the required application. During this procedure, you need to tick the corresponding checkbox at the appropriate confirmation frame (depending on the project source type used) in order to enable the ZDT deployment option:
for deployment via local file or direct URL
Note that while performing this for the first time for the already existing application, deployed to the ROOT context, all the previous data will normally be erased and overwritten with the “bare” app installation (for the deployment via archive/URL only)
the Enable zero-downtime deployment flag becomes active only when deploying to the ROOT context of your PHP application server. Otherwise, the classic method will be used
while working with VCS repos, the chosen deployment mode will be remembered and used for all further auto-updates of this application until you change it manually
generally, we recommend not to use the “hard-coded” absolute paths in your app’s code and configs while using the atomic deployment feature, for ensuring it remains operative regardless of the project’s directory name
3. During the initial deployment, a ROOT_timestamp (i.e. ROOT_year.mm.dd-hh.mm.ss) folder and a special ROOT file as asymlink to this folder are created inside the webroot directory of your application server.
As normal, the application is ready to handle requests just after the deployment process is finished.
4. During the second deployment (i.e. when deploying an update), a new ROOT_timestamp folder is created - in such a way, the actual application version and customers, that are currently working with it, are not influenced.
Just after the new files are unpacked, symlink switches to this new folder, redirecting all the newly received requests to it. Herewith, the first folder is kept for processing the “old” users’ sessions (i.e. where handling started before the symlink switching).
Note that while updating an app version using archive/URL, all the comprised user-generated content (if there is any) should be manually moved to the newly created app directory from the older one, stored alongside (herewith, previously such an operation implies the full overriding of all the context data).
If using VCS, the app’s directory content is entirely copied (both tracked and untracked files), so no manual operations are required. However, we recommend to adopt the practice of the .gitignore list usage for the unnecessary files of your project, as this would save you some amount of resources and time during repetitive re-deploys.
Delving into the details of technical implementation, the atomic deployment option support at GPUonCLOUD is ensured by the following adjustments, applied to the corresponding PHP instances:
The appropriate functionality is handled with the help of the mod_realdoc module, which controls the abovementioned symlink switching. It can be additionally configured (if required) through the GPUonCLOUD dashboard within the conf.d > mod_realdoc.conffile.
Tip: Here, the RealpathEvery parameter defines the period of time for which the symbolic link path is stored and the frequency of its refreshing. It’s default value (0, as denoted within the code comments) was changed to 2 for ensuring all of the required operations (i.e. deployment and switching) to be completed before redirecting the requests to the new project version and as such, preventing the I/O slowdowns.
This value can be easily changed to your custom one if needed (just do not forget to restart your app server node for its appliance). However, if using the ZDT deployment feature, we do not recommend to set it too high, as this would cause the delays in symlink switching.
Comparison and Summary
To prove the benefits of the ZDT update approach, a simple load test was run, with the following parameters as a basis:
application - a basic version of WordPress CMS deployed (i.e. its default distribution with no heavy content comprised)
load generation tool - Apache JMeter, configured to continuously send the required amount of concurrent requests to our application during the redeployment process
time frame - the test starts a short time before the redeployment process is run and finishes a few seconds after it is completed
So, let’s evaluate the results for both deployment methods with the simple statistics we’ve received.
Let’s start with the most commonly used variant of the project deployment, namely - classic, i.e. installation from a single archived package with no extra options like ZDT enabled:
As you can see, we actually get pretty good results:
quick and steady response time (the blue graph), only 1.2 seconds on average
fast restoration to the normal operability (i.e. when all of the incoming requests are successfully processed (the green line) with no errors (the red graph) occurred) after the new package deployment
fails to appear for two seconds only - see the red line spike (however, deploying a more heavy and content-replete project will increase this interval for certain)
Now, let’s perform the same test with the second competitor - ZDT. For a better comparison perception, we’ll keep the same color legend as before:
Response time remains stable and almost unchanged, but you can notice its slight enlargement during the update procedure, which is caused by the additional deployment process running alongside the serving of requests. Herewith, there isn’t even a single errorduring the whole test.
So, in such a way, we can assume that zero downtime deployment overcomes the problem of failed requests during application redeployment, simultaneously keeping the average response time on the same level. In addition, the atomic option leaves you a possibility to save all of the user-generated content, located inside the application directory, and easily move it to the new app’s version if necessary (while the classic method normally implies just the entirely new app version deployment)
You may also notice, that the minimum requests’ handling time for the classic method is significantly lower than for the atomic one and, therefore, seems to bring better performance. But don’t be mislead, as it’s just a side effect of the failed requests presence (where serving time is also counted, despite it being not processed), while the average response time is almost the same for both methods.
Next, let’s repeat our test for the second GPUonCLOUD deployment type (i.e. if using Git/SVN repos) in order to find out whether ZDT retains its advantages in this case. And again we’ll start with the classic method:
As the deployment sources are placed at the remote resource, this will require a little more time compared to the installation from the already uploaded archive, which, actually, helps us to clearly see the difference. The response time now has a pretty long drop down (for nearly 4 seconds in our case), caused by the unavailability of the application (you can see that incoming requests start to fail at the same time - this is shown with a spike at the errors graph). Everything else remains similar to the previous deployment type.
Note that unlike the archive deploy (where the old project is entirely removed before redeployment, which will always cause downtime), here the update procedure assumes changing of the differing files only. Therefore, you may not face any interruption in the service work if the files that are required to be changed, are currently unused.
Finally, the last test for the ZDT deployment approach via VCS also goes in line with our expectations by bringing a stable response time with its small incrementation during the simultaneous running of such operations as users’ sessions handling and project copying/updating.
At the same time, you can see that no errors appeared and all of the incoming requests are successfully processed.
Now, when you have all the information (both raw technical and visualized in graphs practical one) on the investigation and have seen how it’s easy to use the ZDT option within GPUonCLOUD Cloud, it’s time to summarize and make a conclusion on the key benefits it brings for your PHP app’s hosting:
ZDT doesn’t require any additional resources like separate instances/tools for being applied - all you need is just enough disk space for storing two project versions (current and the previous one). It could be considered as an almost free of charge solution, especially compared with the majority of other possible options, which may require additional app servers, balancers, external services, etc.
the deployment remains just as simple as before - no additional configurations or human intervention is required
the time needed for the atomic deployment is exactly the same as for the classic method, so no delays are expected
finally, Zero-Downtime deployment stands by its name by ensuring it’s completely implicit for your customers with an errorless updating procedure (in contrast to the classic variant, which, without being additionally improved, causes a pretty big amount of errors even in the case of a small application redeployment)