kno*_*orv 55 java deployment grails resin tomcat
部署大型Java webapp(> 100 MB .war)时,我目前使用以下部署过程:
关于这种方法的好处:
关于这种方法的坏事:
我想找到一个具有以下属性的部署过程:
题:
Asa*_*aph 30
由于这个答案是第一次编写的,因此出现了将war文件部署到tomcat并且停机时间为零的更好方法.在最新版本的tomcat中,您可以在war文件名中包含版本号.因此,例如,您可以同时部署文件ROOT##001.war
和ROOT##002.war
相同的上下文.之后的所有内容都##
被tomcat解释为版本号,而不是上下文路径的一部分.Tomcat将保持您的应用程序的所有版本运行,并为最新版本提供新的请求和会话,同时在他们开始使用的版本上优雅地完成旧请求和会话.指定版本号也可以通过tomcat管理器甚至catalina ant任务完成.更多信息在这里.
Rsync往往对压缩文件无效,因为它的delta传输算法会查找文件中的更改,并且对未压缩文件进行小的更改,可以大大改变生成的压缩版本.因此,如果网络带宽被证明是瓶颈,那么rsync一个未压缩的war文件而不是压缩版本可能是很有意义的.
使用Tomcat管理器应用程序进行部署有什么问题?如果您不想将整个war文件从远程位置直接上传到Tomcat管理器应用程序,则可以将它(由于上述原因未压缩)rsync到生产盒上的占位符位置,将其重新打包为战争,以及然后在当地交给经理.Tomcat附带了一个很好的ant任务,允许您使用Tomcat管理器应用程序编写脚本部署.
您的方法中还有一个未提及的缺陷:当您的应用程序部分部署时(在rsync操作期间),您的应用程序可能处于不一致状态,其中更改的接口可能不同步,新的/更新的依赖项可能此外,根据您的rsync作业需要多长时间,您的应用程序实际上可能会重启多次.您是否意识到您可以而且应该关闭Tomcat中的listen-for-changed-files-restart行为?实际上不建议用于生产系统.您始终可以使用Tomcat管理器应用程序手动或以脚本方式重新启动应用程序.
当然,重启期间用户将无法使用您的应用程序.但是,如果您对可用性非常关注,那么您肯定会在负载均衡器后面有冗余的Web服务器.部署更新的war文件时,您可以暂时让负载均衡器将所有请求发送到其他Web服务器,直到部署结束.冲洗并重复其他Web服务器.
Ste*_*n C 20
已经注意到,当将更改推送到WAR文件时,rsync不能正常工作.原因是WAR文件本质上是ZIP文件,默认情况下是使用压缩成员文件创建的.成员文件的小变化(压缩前)会导致ZIP文件出现大规模差异,导致rsync的delta-transfer算法无效.
一种可能的解决方案是使用jar -0 ...
创建原始WAR文件.该-0
选项告诉jar
命令在创建WAR文件时不压缩成员文件.然后,当rsync
比较WAR文件的旧版本和新版本时,delta-transfer算法应该能够创建小差异.然后安排rsync以压缩形式发送差异(或原始文件); 例如,使用rsync -z ...
或下面的压缩数据流/传输.
编辑:根据WAR文件的结构,可能还需要使用它jar -0 ...
来创建组件JAR文件.这适用于经常更改(或简单重建)的JAR文件,而不是稳定的第三方JAR文件.
从理论上讲,此过程应该比发送常规WAR文件有显着改进.在实践中我没有试过这个,所以我不能保证它会起作用.
缺点是部署的WAR文件会大得多.这可能会导致webapp启动时间延长,但我怀疑这种影响是微不足道的.
完全不同的方法是查看您的WAR文件,看看您是否可以识别可能(几乎)永远不会更改的库JAR.将这些JAR从WAR文件中取出,并将它们单独部署到Tomcat服务器的common/lib
目录中; 例如使用rsync
.
ide*_*tor 13
在任何需要停机的环境中,您肯定会运行某种服务器集群,以通过冗余提高可靠性.我将主机从群集中取出,更新它,然后将其重新放回群集中.如果您的更新无法在混合环境中运行(例如,数据库中需要进行不兼容的架构更改),则必须至少暂时关闭整个站点.诀窍是在放弃原件之前调出更换过程.
以tomcat为例 - 您可以使用CATALINA_BASE定义一个目录,其中将找到所有tomcat的工作目录,与可执行代码分开.每次部署软件时,我都会部署到一个新的基本目录,这样我就可以在旧代码旁边的磁盘上驻留新代码了.然后我可以启动另一个指向新基本目录的tomcat实例,让所有内容启动并运行,然后将旧进程(端口号)与负载均衡器中的新进程交换.
如果我担心在交换机上保留会话数据,我可以设置我的系统,使每个主机都有一个合作伙伴,它可以复制会话数据.我可以删除其中一个主机,更新它,重新启动它以便它选择备份会话数据,然后切换两个主机.如果我在群集中有多对,我可以丢弃所有对中的一半,然后进行批量切换,或者我可以一次执行一对,具体取决于发布的要求,企业的要求等但就个人而言,我更愿意让最终用户偶尔失去一个活跃的会话,而不是试图通过完整的会话进行升级.
这是IT基础架构,发布流程复杂性和开发人员工作之间的权衡.如果您的群集足够大并且您的愿望足够强大,那么设计一个可以换掉的系统就足够了,大多数更新都没有停机时间.大型模式更改通常会导致实际的停机时间,因为更新的软件通常无法容纳旧模式,您可能无法将数据复制到新的数据库实例,执行模式更新,然后将服务器切换到新的数据库,在从中克隆新数据库之后,您将错过任何写入旧数据的数据.当然,如果你有资源,你可以让任务开发人员修改新应用程序,为所有更新的表使用新的表名,并且你可以在实时数据库上放置触发器,这将正确地用数据更新新表.它由先前版本写入旧表(或者可以使用视图来模拟另一个模式).启动新的应用服务器并将其交换到群集中.如果您有开发资源来构建它们,那么您可以玩很多游戏以最大限度地减少停机时间.
在软件升级过程中减少停机时间的最有用机制可能是确保您的应用程序可以在只读模式下运行.这将为您的用户提供一些必要的功能,但让您能够进行需要数据库修改等的系统范围的更改.将您的应用程序置于只读模式,然后克隆数据,更新架构,针对新数据库启动新的应用服务器,然后切换负载均衡器以使用新的应用服务器.您唯一的停机时间是切换到只读模式所需的时间以及修改负载均衡器配置所需的时间(大多数可以在没有任何停机时间的情况下处理它).
cet*_*nar 10
我的建议是将rsync与爆炸版本一起使用,但部署war文件.
在JBoss容器(基于Tomcat)中建议用旧的战争替换旧的战争,因为它是原子和快速操作,并且当部署者启动整个应用程序时将确保处于已部署状态.