PHP 应用程序的 ZeroDownTime (ZDT) 部署持续交付

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观


现代企业网络服务的提供基于 24/7 全天候可访问性,这对于那些依赖于频繁重新部署(即更新)的企业来说尤为重要。通常,这时候你的服务器宕机,造成的不仅仅是暂时的利润损失,还会降低用户的信任度,这对于任何付费服务来说都是不能接受的。

capistrano、fabric 等工具的一个巨大分支可以帮助您解决这个问题——例如,通过将多个服务器设置为负载均衡器作为前端,这将交替更新它们。然而,所有这些公用事业都有一定的额外要求,这会导致费用增加,并且需要一些时间和专业知识才能进行整合和适当调整。显然,这样的实现显得相当复杂,需要大量额外的资源,因此需要更好的方法。

最近,该编程语言的创始人同时也是我们的技术顾问 rasmus lerdorf 为运行在 apache 之上的 php 应用程序提出了这一领域的全新 方法 。这在 etsy 得到积极使用,因此,作为一个经过实战检验的解决方案,它被用作 jelastic 中零停机部署功能实施的基础。其主要思想在于以下两点:

  • 每次运行新的部署过程时,相应应用程序的文件都会被复制,并存储在单独的服务器目录中(根据其创建日期/时间自动命名,以便于识别)。
  • 一个特殊请求的重定向器,称为 符号链接 (即符号链接),在每次更新后在不同的应用程序版本之间切换,指向当前应该使用的版本。

通过这种方式,可以无缝部署更新的项目文件,同时初始代码版本继续工作并处理用户会话。当部署完全完成时,符号链接立即切换到已成功部署的应用程序的最新版本,开始将所有传入请求重定向到它。所有这些共同使部署过程对您的客户而言完全是原子的和隐含的,同时使您从执行大量预想的手动操作中解脱出来。



请注意 ,此功能的可用性需要 jelastic 平台版本 3.3 或更高版本,并且取决于您的托管服务提供商的设置。

下面,我们将通过相应地描述 zdt 部署工作流以及此功能在 jelastic 中的实现方式来更详细地发现此机制。为了确保这种方法是有效的,在本文的最后你可以找到 zdt 和经典部署方法的比较,通过在 jmeter 的帮助下运行一组负载测试来执行。

那么,让我们开始吧!

zdt 部署工作流

首先,我们将更具体地考虑上述 php 零停机部署机制实际上如何在 jelastic 上运行——让我们用一个真实的例子逐步检查所有这些过程。

  1. 首先,您需要一个 php 环境( 新的 或已有的)——我们将在本例中使用 apache:

  1. 接下来,继续部署所需的应用程序。在此过程中,您需要在适当的确认框中勾选相应的复选框(取决于使用的项目源类型)以启用 zdt 部署选项:

注意: 当第一次为已经存在的应用程序执行此操作时,部署到 上下文,所有以前的数据通常会被删除并被“裸”应用程序安装覆盖(仅通过存档/url 部署)。

注意

  • 仅当部署到 PHP 应用程序服务器的 上下文时, 启用零停机部署 标志才会激活。否则,将使用经典方法
  • 在使用 vcs repos 时,选择的部署模式将被记住并用于此应用程序的所有进一步 自动更新, 直到您手动更改它
  • 通常,我们建议在使用 zdt 部署功能时不要在应用程序代码和配置中使用“硬编码”绝对路径,以确保无论项目的目录名称如何,它都能保持运行
  1. 在初始部署期间 ,会在应用程序服务器的 webroot 目录中创建一个 root_timestamp (即 root_year.mm.dd-hh.mm.ss )文件夹和一个作为该文件夹符号链接的特殊 文件。

与往常一样,应用程序在部署过程完成后立即准备好处理请求。

如果在 目录中导航,如上图圈出的,将查看当前使用的应用程序版本的内容,即每次切换符号链接时都会更改。

如果 通过 ssh 进入您的应用程序服务器的容器并为您的 webroot 文件夹执行长格式文件列表命令,则可以清楚地看到这一点,即:

ls -l /var/www/webroot


通过这种方式,您可以轻松找到符号链接,因为它在列表中有颜色标记,并可以查看实际的重定向路径。

  1. 在第二次部署期间 (即部署更新时),将创建一个新的 root_timestamp 文件夹——这样一来,当前使用它的实际应用程序版本和客户不会受到影响。

就在新文件解压之后,符号链接切换到这个新文件夹,将所有新收到的请求重定向到它。因此,保留第一个文件夹用于处理“旧”用户的会话(即在符号链接切换之前开始处理的地方)。

请注意 ,在使用 archive/url 更新应用程序版本时,所有包含的用户生成的内容(如果有的话)都应手动从旧的应用程序目录移动到新创建的应用程序目录,并存储在旁边(在此之前,这样的操作意味着完全覆盖所有上下文数据)。

如果使用 vcs,应用程序的目录内容将被完全复制(跟踪和未跟踪的文件),因此不需要手动操作。但是,我们建议对项目中不需要的文件采用 .gitignore 列表用法的做法,因为这会在重复重新部署期间为您节省一些资源和时间。

  1. 以下所有部署都 将以类似的方式执行。在每个过程中,最旧的项目文件夹被删除,同时为最新的项目版本添加了一个新的 root_timestamp 目录。

通过这种方式,部署的应用程序只有 2 个版本——最新版本和之前版本——同时存储在应用程序服务器中(但是,当不再需要旧版本时,也可以轻松地手动将其删除)。这确保没有额外的磁盘空间消耗。

注意: 如果您想避免某些项目版本被自动删除,只需在运行新部署之前重命名相应的文件夹即可。

所有操作都是完全自动化的,因此不需要额外的开发人员参与,而部署本身是在“软”模式下执行的,即即使不需要重新启动应用程序服务器,因此也没有任何应用程序停机。

php 服务器上的 zdt 实现

深入研究技术实现的细节,通过以下调整确保 jelastic 的零停机部署选项支持,应用于相应的 php 实例:

  • apache php 的 适当功能是在 mod_realdoc 模块的帮助下处理的,该模块控制上述符号链接切换。它可以通过 conf.d > mod_realdoc.conf 文件中的 jelastic 仪表板进行额外配置(如果需要)。


提示: 在这里, realpathevery 参数定义了符号链接路径存储的时间段及其刷新频率。它的默认值( 0 ,如配置注释中所示)更改为 2 以确保在将请求重定向到新项目版本之前完成所有必需的操作(即部署和切换),因此,防止 i/减速。

如果需要,这个值可以很容易地更改为您的自定义值(只是不要忘记为其设备重新启动应用程序服务器节点)。但是,如果使用 zdt 部署功能,我们 不建议 将其设置得太高,因为这会导致符号链接切换延迟。

有关此模块细节的更多信息,请访问其源 页面

  • nginx-php 在这里,zdt 部署是通过内置功能确保的,没有包含额外的模块——相应的设置可以在 conf > nginx.conf 文件的最后找到:

现在,正如您了解所有这些工作原理一样,我们可以比较经典部署方法和 zdt 部署方法。

比较总结

为了证明 zdt 更新方法的好处,运行了一个简单的负载测试,以下列参数为基础:

  • 应用程序 ——部署的 wordpress cms 的基本版本(即它的默认分发,不包含大量内容)。
  • 负载生成工具 apache jmeter ,配置为在重新部署过程中不断向我们的应用程序发送所需数量的并发请求。
  • 时间范围 —— 测试在重新部署过程运行之前的一小段时间开始,并在它完成后几秒钟结束。

因此,让我们使用收到的简单统计数据来评估这两种部署方法的结果。

存档部署

让我们从最常用的项目部署变体开始,即 – 经典 ,即从单个存档包安装,不启用 zdt 等额外选项:

如您所见,我们实际上得到了很好的结果:

  • 快速稳定的 响应时间 (蓝色图表),平均只有 1.2
  • 新包部署后快速恢复到正常可操作性(即当所有传入请求都被 成功处理 (绿线)且没有 错误 (红图)发生时)
  • 仅两秒未出现 – 见红线峰值(但是,部署更重且内容更丰富的项目肯定会增加此间隔)

现在,让我们对第二个竞争对手 zdt 进行相同的测试。为了更好的比较感知,我们将保留与以前相同的颜色图例:


响应时间 保持稳定且几乎没有变化,但您可以注意到它在更新过程中略有增加,这是由于在请求服务的同时运行的额外部署过程造成的。至此,整个测试过程中甚至没有出现一个 错误

因此,通过这种方式,我们可以假设零停机部署克服了应用程序重新部署期间请求失败的问题,同时将平均响应时间保持在同一水平。此外,zdt 选项让您可以保存位于应用程序目录内的所有用户生成的内容,并在必要时轻松地将其移动到新应用程序的版本(而经典方法通常只意味着全新的应用程序版本部署)

您可能还会注意到 ,经典方法的最小请求处理时间明显低于 zdt 方法,因此,似乎可以带来更好的性能。但不要被误导,因为这只是失败请求存在的副作用(服务时间也被计算在内,尽管它没有被处理),而这两种方法的平均响应时间几乎相同。

vcs 部署

接下来,让我们对第二种 jelastic 部署类型(即,如果使用 git/svn repos)重复我们的测试,以查明 zdt 在这种情况下是否保留其优势。我们将再次从 经典 方法开始:

由于部署源位于远程资源,与从已上传的存档安装相比,这将需要更多时间,这实际上有助于我们清楚地看到差异。由于应用 程序 不可用(您可以 看到 传入的请求同时开始失败——这在 误差 图)。其他一切都与以前的部署类型相似。

请注意 ,与归档部署(其中旧项目在重新部署之前被完全删除,这总是会导致停机)不同,这里的更新过程假定仅更改不同的文件。因此,如果需要更改的文件当前未使用,您可能不会面临服务工作的任何中断。

最后,最后一次通过 vcs 对 zdt 部署方法的测试也符合我们的预期,在用户会话处理和项目复制/更新等操作同时运行时, 响应时间 稳定且增量小。

同时,您可以看到没有出现任何 错误 ,并且所有传入的请求都已 成功处理

结论

现在,当您获得有关调查的所有信息(包括原始技术信息和图表中的可视化信息)并了解在 jelastic Cloud 中使用 zdt 选项是多么容易时,是时候总结并得出结论了它的主要好处为您的 php 应用程序托管带来:

  • zdt 不需要任何额外的资源,如单独的实例/工具来应用——您只需要足够的磁盘空间来存储两个项目版本(当前和以前的版本)。它可以被视为几乎免费的解决方案,尤其是与大多数其他可能的选项相比,后者可能需要额外的应用程序服务器、平衡器、外部服务等。
  • 部署仍然和以前一样简单——不需要额外的配置或人工干预。
  • zdt 部署所需的时间与经典方法完全相同,因此预计不会有延迟。
  • 最后,零停机时间部署通过无错误的更新过程确保它对您的客户完全隐含(与经典变体相比,它在没有额外改进的情况下会导致相当多的错误,即使在一个小的应用程序重新部署)。

通过这种方式,zdt 部署使用使您的项目更新完全轻松且对客户不可见,从而帮助您从您的应用程序中获得最大收益!