在最短的停机时间内部署 Java Web 应用程序的最佳实践?

2022-08-31 16:55:35

部署大型 Java webapp(>100 MB .war)时,我当前使用以下部署过程:

  • 应用程序 .war 文件在开发计算机上本地展开。
  • 扩展的应用程序是从开发计算机到实时环境的 rsync:ed。
  • 实时环境中的应用程序服务器在 rsync 后重新启动。此步骤不是严格需要的,但是我发现在部署时重新启动应用程序服务器可以避免“java.lang.OutOfMemoryError:PermGen空间”,因为频繁的类加载。

这种方法的好处:

  • rsync 可最大程度地减少从开发计算机发送到实时环境的数据量。上传整个 .war 文件需要十分多钟,而上传一个 rsync 则需要几秒钟。

这种方法的坏处:

  • 当 rsync 运行时,应用程序上下文将重新启动,因为文件已更新。理想情况下,重新启动应该在 rsync 完成后进行,而不是在它仍在运行时。
  • 应用服务器重启会导致大约两分钟的停机时间。

我想查找具有以下属性的部署过程:

  • 部署过程中的停机时间最短。
  • 上传数据所花费的时间最少。
  • 如果部署过程特定于应用服务器,则应用服务器必须是开源的。

问题:

  • 根据规定的要求,最佳部署过程是什么?

答案 1

更新:

自从这个答案首次编写以来,出现了一种更好的方法,可以在零停机时间的情况下将战争文件部署到tomcat。在最新版本的tomcat中,您可以在战争文件名中包含版本号。例如,您可以同时将文件和部署到同一上下文中。之后的所有内容都被 tomcat 解释为版本号,而不是上下文路径的一部分。Tomcat 将保持应用程序的所有版本运行,并将新请求和会话提供给完全启动的最新版本,同时在它们开始的版本上优雅地完成旧请求和会话。指定版本号也可以通过tomcat管理器甚至catalina ant任务来完成。更多信息请点击这里ROOT##001.warROOT##002.war##

原始答案:

Rsync往往对压缩文件无效,因为它的增量传输算法会查找文件中的更改,而未压缩文件的微小更改可能会极大地改变生成的压缩版本。出于这个原因,如果网络带宽被证明是一个瓶颈,那么rsync一个未压缩的war文件而不是压缩版本可能是很有意义的。

使用 Tomcat 管理器应用程序执行部署有什么问题?如果您不想将整个 war 文件从远程位置直接上传到 Tomcat 管理器应用程序,则可以将其 rsync(由于上述原因而未压缩)到生产框中的占位符位置,将其重新打包为 war,然后将其交给本地管理器。有一个很好的蚂蚁任务,随Tomcat一起提供,允许您使用Tomcat管理器应用程序编写部署脚本。

您的方法中还有一个您没有提到的缺陷:当您的应用程序部分部署时(在 rsync 操作期间),您的应用程序可能处于不一致的状态,其中更改的接口可能不同步,新的/更新的依赖项可能不可用,等等。此外,根据 rsync 作业花费的时间,应用程序实际上可能会重新启动多次。您是否知道可以并且应该关闭 Tomcat 中的侦听已更改文件和重新启动行为?实际上不建议将其用于生产系统。您始终可以使用 Tomcat 管理器应用程序手动或按脚本方式重新启动应用程序。

当然,在重新启动期间,您的应用程序将对用户不可用。但是,如果您非常担心可用性,那么您肯定会在负载平衡器后面拥有冗余的Web服务器。部署更新的 war 文件时,可以暂时让负载均衡器将所有请求发送到其他 Web 服务器,直到部署结束。冲洗并重复您的其他Web服务器。


答案 2

已经注意到,在将更改推送到 WAR 文件时,rsync 不能正常工作。这样做的原因是 WAR 文件本质上是 ZIP 文件,并且缺省情况下是使用压缩成员文件创建的。对成员文件的微小更改(在压缩之前)会导致 ZIP 文件中出现大规模差异,从而使 rsync 的增量传输算法无效。

一种可能的解决方案是用于创建原始 WAR 文件。该选项告诉命令在创建 WAR 文件时不压缩成员文件。然后,在比较 WAR 文件的旧版本和新版本时,增量传输算法应该能够创建较小的差异。然后安排rsync以压缩形式发送差异(或原始文件);例如,使用或压缩数据流/传输下面。jar -0 ...-0jarrsyncrsync -z ...

编辑:根据 WAR 文件的结构,可能还需要使用来创建组件 JAR 文件。这将适用于经常更改(或只是重建)的JAR文件,而不是稳定的第三方JAR文件。jar -0 ...

从理论上讲,与发送常规 WAR 文件相比,此过程应有显著改进。在实践中,我没有尝试过这个,所以我不能保证它会起作用。

缺点是部署的 WAR 文件将明显变大。这可能会导致Webapp启动时间更长,尽管我怀疑这种影响是微不足道的。


完全不同的方法是查看您的 WAR 文件,看看您是否可以识别可能(几乎)永远不会更改的库 JAR。将这些 JAR 从 WAR 文件中取出,并将它们分别部署到 Tomcat 服务器的目录中;例如,使用 .common/librsync


推荐