ZDT Deployment for PHP

ZDT Deployment for PHP

Modern web services need to be accessible at all times. However, during project re-deployment (i.e., updates), applications can go down or return errors until the process is complete. Tools like Capistrano and Fabric can address this, but they often require additional time, expense, and specialist knowledge to integrate and configure properly. For example, setting up multiple servers with a load balancer to exclude servers during deployment can be complex and resource-intensive.

A simpler solution for PHP applications running on Apache was proposed by Rasmus Lerdorf, the creator of PHP and our technical advisor. This method, actively used at Etsy and battle-tested, forms the basis for the Zero Downtime & Atomic Deployment feature on our platform. The key points of this approach are:

1. File Duplication During Deployment:

  • Each time a new deployment process is run, the application’s files are duplicated and stored in a separate server directory. This directory is automatically named based on its creation date and time for easy identification.

2. Symbolic Link (Symlink) Switching:

  • A special request redirector, called a symlink (symbolic link), switches between different application versions after each update, pointing to the version that should be currently used.

Symlink Switching

In this way, the updated project files can be seamlessly deployed while the original code version continues to operate and handle user sessions. Once the deployment is fully completed, the symlink instantly switches to the latest version of the successfully deployed application, redirecting all incoming requests to it. This approach ensures that the deployment process is fully atomic and transparent to your customers, relieving you from performing numerous manual operations.

Below, we’ll explore this mechanism in more detail by describing:

Let’s go on!

ZDT Deployment Workflow

First, let’s look at how the PHP zero-downtime deployment mechanism operates on the platform. We’ll examine this process step-by-step with a real example.

Step 1. Begin by setting up a PHP environment (either a new or an existing one). For this example, we’ll use Apache.

Select application server

Step 2. Proceed with deploying the required application. During the deployment process, ensure to tick the appropriate checkbox in the confirmation frame (depending on the project’s source type) to enable the ZDT deployment option:

For deployment via local file or direct URL:

Enable Zero-Downtime Deployment

Note: When performing this for the first time on an existing application deployed to the ROOT context, all previous data will typically be erased and overwritten with the new app installation (applies to deployment via archive/URL only).

For deployment via VCS (e.g. from GIT/SVN or Bitbucket repo):

Deployment via VCS

Note:

  • The 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.
  • When working with VCS repositories, 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 using “hard-coded” absolute paths in your app’s code and configs while using the atomic deployment feature to ensure it remains operative regardless of the project’s directory name.

Step 3. During the initial deployment, a folder named ROOT_timestamp (e.g., ROOT_year.mm.dd-hh.mm.ss) and a special ROOT file acting as a symlink to this folder are created inside the webroot directory of your application server.

Once the deployment process is finished, the application is ready to handle requests as usual.

Webroot

Step 4. During the second deployment (i.e., when deploying an update), a new folder named ROOT_timestamp is created. This ensures that the current application version and the customers using it remain unaffected.

Root_timestamp

Immediately after the new files are unpacked, the symlink switches to this new folder, directing all newly received requests to it. Meanwhile, the first folder continues processing sessions for “old” users, i.e., those who began their session before the symlink switch.

Note: When updating an app version using an archive or URL, any user-generated content should be manually transferred to the newly created app directory from the older one, which is stored alongside. Previously, such an operation involved the complete overriding of all context data.

If using version control systems (VCS), all content in the app’s directory, including tracked and untracked files, is fully copied, eliminating the need for manual operations. However, it’s advisable to utilize the .gitignore list to exclude unnecessary files from your project. This practice saves resources and time during repetitive re-deploys.

Step 5. Subsequent atomic deployments follow the same process. Each deployment involves removing the oldest project folder while adding a new ROOT_timestamp directory for the most recent project version.

This method ensures that only two versions of the deployed application—the latest and the previous one—are stored within the app server simultaneously. The older version can be manually removed when it is no longer needed, preventing any unnecessary disk space consumption.

Note: If you want to prevent a specific project version from being automatically removed, simply rename the corresponding folder before initiating the new deployment.Rename Corresponding Folder

All operations are fully automated, requiring no additional involvement from developers. The deployment process is executed smoothly, without the need for an app server restart, ensuring zero application downtime.

ZDT Implementation at PHP Servers

The atomic deployment option for Apache PHP instances is facilitated by the mod_realdoc module. This module manages the symlink switching process and can be further configured through the platform dashboard in the conf.d > mod_realdoc.conf file.

ZDT Implementation

TIP: The RealpathEvery parameter in the mod_realdoc module determines how frequently the symbolic link path is refreshed. By default, its value is set to 0, but for ZDT deployment, it’s adjusted to 2. This ensures that all deployment and switching operations are completed before redirecting requests to the new project version, preventing I/O slowdowns.

If necessary, you can customize this value, but avoid setting it too high as it may cause delays in symlink switching. Remember to restart your app server node after making any changes to apply them.

For additional details about this module, please refer to its source page. Regarding NGINX-PHP, atomic deployment relies on built-in functionality without requiring additional modules. You can find the corresponding settings at the end of the conf > nginx.conf file. With this understanding, let’s compare both classic and atomic deployment methods.

Comparison and Summary

To demonstrate the advantages of the ZDT update approach, we conducted a straightforward load test with the following key parameters:

  1. Application: We used a basic version of WordPress CMS for the test, deploying its default distribution without any heavy content.
  2. Load Generation Tool: Apache JMeter was configured to continuously send the necessary amount of concurrent requests to our application throughout the redeployment process.
  3. Time Frame: The test commenced shortly before initiating the redeployment process and concluded a few seconds after its completion.

Let’s delve into the most widely used method of project deployment – the classic approach, also known as installation from a single archived package without additional features like ZDT enabled:

Classic Approach

In this scenario, we observe commendable results:

  • Swift and consistent response time (depicted by the blue graph), averaging just 1.2 seconds.
  • Rapid restoration to normal operation, where all incoming requests are successfully processed (illustrated by the green line) with no encountered errors (depicted by the red graph).
  • A brief spike in response time lasting only two seconds, as highlighted by the red line (though deploying a more content-rich project could potentially extend this interval).

Now, let’s conduct the identical test using the second contender – ZDT. To facilitate clearer comparison, we’ll maintain the same color legend as previously used:

ZDT

The response time remains stable and nearly unchanged, albeit with a slight increase during the update process, attributed to concurrent deployment activities alongside request serving. Remarkably, no errors occur throughout the entire test duration.

Hence, zero downtime deployment effectively mitigates the issue of failed requests during application updates, while maintaining an average response time consistent. Moreover, the atomic approach affords the flexibility to retain all user-generated content within the application directory, facilitating seamless migration to the new application version as needed – a capability absent in the conventional deployment method.

Indeed, you may observe that the classic method exhibits a notably lower minimum request handling time compared to the atomic approach, suggesting superior performance. However, this observation can be misleading. The discrepancy arises due to the presence of failed requests, where the serving time is included in the calculation despite the requests not being processed. In reality, the average response time remains nearly identical for both methods.

VCS Deployment

Now, let’s replicate our test for the second type of deployment, which involves using version control systems (VCS) such as Git or SVN. We’ll begin with the classic deployment method:

VCS Deployment

Since the deployment sources are located in a remote repository, this process naturally takes longer compared to installing from an uploaded archive. This delay allows us to more clearly observe the differences. During this process, the response time experiences a significant drop (nearly 4 seconds in our case), indicating the unavailability of the application. This is reflected in the spike in the errors graph, indicating a failure to handle incoming requests during this period. Otherwise, the performance remains largely consistent with the previous deployment method.

Note: Unlike archive deployment, where the old project is entirely replaced before redeployment, causing downtime, in VCS deployment, only the differing files are updated. Consequently, if the files requiring changes are not currently in use, there may be no interruption in service.

Finally, the last test for ZDT deployment via VCS aligns with our expectations, maintaining a stable response time with a slight increase during simultaneous operations, such as handling user sessions and updating the project.

ZDT Deployment via VCS

Additionally, no errors occurred, and all incoming requests were successfully processed.

Conclusion

Alright, we’ve delved into the technical nitty-gritty (raw data, visualizations, and practical applications) of ZDT, and you’ve witnessed its user-friendly implementation within our platform. Now, let’s condense this information and highlight the significant advantages it brings to your PHP application’s hosting environment.

  • Cost-Conscious Choice: ZDT eliminates the need for additional resource allocation like separate instances or tools. You simply require sufficient disk space to store two project versions (current and previous). Compared to other solutions potentially demanding extra app servers, balancers, or external services, ZDT emerges as a practically free-of-charge option.
  • Deployment Made Easy: The deployment process remains as streamlined as ever. There’s no requirement for additional configurations or manual intervention, ensuring a smooth and hassle-free experience.
  • Atomic Speed and Zero Downtime: ZDT upholds its promise – deployment speed remains identical to the classic method, preventing any delays for your users. Even more importantly, ZDT lives up to its namesake by guaranteeing a completely transparent update process for your customers. This stands in stark contrast to the classic approach, which can introduce errors even during minor application deployments.
  • The ZDT Advantage: By incorporating ZDT deployment, you transform project updates into a seamless and invisible operation for both your team and your customers. This empowers you to maintain optimal application performance and deliver a consistently exceptional user experience.