Pergunta

Ao implantar um grande webapp Java (> 100 MB .war) Eu estou atualmente usam o seguinte processo de implantação:

  • A aplicação .war arquivo é expandido localmente na máquina de desenvolvimento.
  • A aplicação expandido é rsync: Ed. Da máquina de desenvolvimento para o meio ambiente ao vivo
  • O servidor de aplicações no ambiente ao vivo é reiniciado após o rsync. Este passo não é estritamente necessário, mas eu descobri que reiniciar o servidor de aplicativos na evita implantação. "Java.lang.OutOfMemoryError: PermGen space", devido ao carregamento de classe frequente

As coisas boas sobre essa abordagem:

  • O rsync minimiza a quantidade de dados enviados do computador de desenvolvimento para o meio ambiente ao vivo. Upload de todo o arquivo .war leva mais de dez minutos, enquanto um rsync leva um par de segundos.

coisas ruins sobre essa abordagem:

  • Quando o rsync está executando o contexto de aplicação é reiniciado desde que os arquivos são atualizados. Idealmente o reinício deve acontecer após o rsync está completa, não quando ele ainda está em execução.
  • O reinício do servidor aplicativo faz com que cerca de dois minutos de tempo de inatividade.

Eu gostaria de encontrar um processo de implantação com as seguintes propriedades:

  • tempo de inatividade mínimo durante o processo de implantação.
  • tempo mínimo gasto upload de dados.
  • Se o processo de implantação é específico servidor de aplicativo, em seguida, o servidor de aplicações deve ser de código aberto.

Pergunta:

  • Dados os requisitos estabelecidos, o que é o processo de implantação ideal?
Foi útil?

Solução

Tem-se observado que o rsync não funciona bem quando empurrar as mudanças para um arquivo WAR. A razão para isso é que os arquivos WAR são essencialmente arquivos zip, e por padrão são criados com arquivos compactados membros. Pequenas alterações para os arquivos membros (antes da compressão) resultam em diferenças de grande escala no arquivo ZIP, tornando ineficaz algoritmo de transferência delta do rsync.

Uma possível solução é usar jar -0 ... para criar o arquivo WAR originais. A opção -0 informa ao comando jar para não comprimir os ficheiros de membros ao criar o arquivo WAR. Então, quando rsync compara as versões antigas e novas do arquivo WAR, o algoritmo de transferência delta deve ser capaz de criar pequenas diffs. Em seguida, organizar que rsync envia os diffs (ou arquivos originais) em forma de comprimido; por exemplo. uso rsync -z ... ou um baixo fluxo de dados comprimidos / transporte.

EDIT: Dependendo de como o arquivo WAR está estruturado, também pode ser necessário usar jar -0 ... para criar arquivos JAR de componentes. Isso se aplica a arquivos JAR que são frequentemente sujeitas a mudanças (ou que simplesmente são reconstruídas), ao invés de arquivos 3o partido JAR estáveis.

Em teoria, este procedimento deve dar uma melhoria significativa sobre o envio de arquivos WAR regulares. Na prática, eu não tentei isso, então eu não posso prometer que ele vai trabalhar.

A desvantagem é que o arquivo WAR implantado será significativamente maior. Isso pode resultar em tempos mais webapp arranque, embora eu suspeite que o efeito seria marginal.


Uma abordagem completamente diferente seria a de olhar para o seu arquivo WAR para ver se você pode identificar JARs biblioteca que são susceptíveis de (quase) nunca mudam. Tome esses JARs fora do arquivo WAR, e implantá-los separadamente no diretório common/lib do servidor Tomcat; por exemplo. usando rsync.

Outras dicas

Update:

Uma vez que esta resposta foi escrita pela primeira vez, a melhor maneira de implantar arquivos de guerra para tomcat com zero downtime surgiu. Em versões recentes do tomcat você pode incluir números de versão em seus nomes de guerra. Assim, por exemplo, você pode implantar o ROOT##001.war arquivos e ROOT##002.war ao mesmo contexto simultaneamente. Tudo após o ## é interpretado como um número de versão por tomcat e não parte do caminho de contexto. Tomcat irá manter todas as versões do seu aplicativo em execução e atender a novos pedidos e sessões para a versão mais recente que é totalmente para cima, enquanto graciosamente completar pedidos antigos e sessões sobre a versão que eles começaram com. Especificando os números de versão também pode ser feito através do gerenciador de tomcat e até mesmo as tarefas Catalina formigas. Mais informações aqui .

Resposta Original:

Rsync tende a ser ineficaz em arquivos compactados, já que é algoritmo de transferência delta olhares para mudanças em arquivos e uma pequena mudança de um arquivo não-comprimido, pode alterar drasticamente a versão resultante comprimido. Por esta razão, pode fazer bom senso ao rsync um arquivo de guerra não-comprimido, em vez de uma versão comprimida, se a largura de banda de rede revela-se um gargalo.

errada do que com o uso do aplicativo gerenciador do Tomcat para fazer suas implementações? Se você não deseja carregar o arquivo inteiro guerra diretamente para o aplicativo gerenciador de Tomcat de um local remoto, você poderia rsync-lo (não comprimido por razões mencionadas acima) para um local espaço reservado na caixa de produção, acondicioná-lo a uma guerra, e em seguida, entregá-lo ao gestor localmente. Existe uma tarefa formiga agradável que vem com o Tomcat que lhe permite implementações de script usando o aplicativo gerenciador de Tomcat.

Há uma falha adicional em sua abordagem que você não mencionou: Enquanto o aplicativo está parcialmente implantado (durante uma operação de rsync), seu aplicativo poderia estar em um estado inconsistente, onde as interfaces mudaram pode estar fora de sincronia, new / dependências atualizados podem estar indisponíveis, etc. Além disso, dependendo de quanto tempo o seu trabalho rsync leva, seu aplicativo pode realmente reiniciar várias vezes. Você está ciente de que você pode e deve desativar o comportamento de escuta e-mudou-files-and-reiniciando no Tomcat? realmente não é recomendado para sistemas de produção. Você sempre pode fazer um reinício script manual ou formiga de sua aplicação usando o aplicativo gerenciador de Tomcat.

O aplicativo estará disponível aos usuários durante uma reinicialização, é claro. Mas se você está tão preocupado com a disponibilidade, certamente você tem servidores web redundantes atrás de um balanceador de carga. Ao implantar um arquivo de guerra atualizado, você poderia ter temporariamente o balanceador de carga enviar todos os pedidos de outros servidores web até que a implantação é longo. Enxágüe e repita para os seus outros servidores web.

Em qualquer ambiente onde o tempo de inatividade é uma consideração, você está certamente executando algum tipo de cluster de servidores para aumentar a confiabilidade através de redundância. Eu levaria uma série fora do cluster, atualizá-lo e, em seguida, jogá-lo de volta para o cluster. Se você tem uma atualização que não pode ser executado em um ambiente misto (alteração de esquema incompatíveis necessário no db, por exemplo), você vai ter que tomar todo o site para baixo, pelo menos por um momento. O truque é para abrir processos de substituição antes de deixar cair os originais.

Usando o tomcat como um exemplo - você pode usar CATALINA_BASE para definir um diretório onde todos os diretórios de trabalho do Tomcat será encontrado, separado do código executável. Toda vez software implantar, eu implantar um novo diretório base para que eu possa ter novo residente código no disco ao lado de código antigo. Posso, então, iniciar outra instância do tomcat que aponta para o novo diretório base, se tudo começou a funcionar, em seguida, trocar o antigo processo (número de porta) com o novo no balanceador de carga.

Se eu estou preocupado em preservar os dados da sessão em todo o interruptor, eu posso configurar meu sistema de tal forma que cada host tem um parceiro para que ele replica os dados da sessão. I pode deixar cair um desses hospedeiros, atualizá-lo, trazê-lo de volta para que ele pega de volta os dados da sessão, e em seguida, mudar os dois hosts. Se eu tenho vários pares no cluster, que pode cair a metade de todos os pares, em seguida, fazer um interruptor de massa, ou eu posso fazer-lhes um par de cada vez, dependendo das exigências da liberação, os requisitos da empresa, etc. . Pessoalmente, porém, eu prefiro apenas permitir que os usuários finais para sofrer a perda muito ocasional de uma sessão ativa em vez de lidar com a tentativa de atualizar com sessões intactas.

É tudo uma troca entre a infra-estrutura de TI, a complexidade do processo de liberação e esforço do desenvolvedor. Se seu cluster é grande o suficiente e seu desejo forte o suficiente, é bastante fácil de projetar um sistema que pode ser trocada sem tempo de inatividade em tudo para a maioria das atualizações. Grande esquema muda frequentemente forçar o tempo de inatividade real, uma vez que o software atualizado geralmente não podem acomodar o esquema antigo, e você provavelmente não pode ir longe com a copiar os dados para uma nova instância db, fazendo a atualização do esquema, e em seguida, mudar os servidores para o novo db, uma vez você vai ter perdido todos os dados gravados no velho depois de o novo db foi clonado a partir dele. Claro, se você tem recursos, você pode encarregar desenvolvedores com modificando o novo aplicativo para usar novos nomes de tabela para todas as tabelas que são atualizados, e você pode colocar gatilhos no lugar no db ao vivo que irá atualizar corretamente as novas tabelas com dados como está escrito para as tabelas antigas pela versão anterior (ou talvez usar exibições para emular um esquema do outro). Criem seus novos servidores de aplicativos e trocá-los para o cluster. Há uma tonelada de jogos que pode jogar a fim de minimizar o tempo de inatividade, se você tem os recursos de desenvolvimento para construí-los.

Talvez o mecanismo mais útil para reduzir o tempo de inatividade durante as atualizações de software é certificar-se de que a sua aplicação pode funcionar em modo de somente leitura. Que irá entregar algumas funcionalidades necessárias para os usuários, mas deixá-lo com a capacidade de fazer alterações no sistema que requerem modificações de banco de dados e tal. Coloque a sua aplicação em modo de somente leitura, então clone os dados, o esquema de atualização, abrir novos servidores de aplicativos contra nova db, em seguida, mudar o balanceador de carga para usar os novos servidores de aplicação. Seu único tempo de inatividade é o tempo necessário para mudar para o modo de somente leitura eo tempo necessário para modificar a configuração do seu balanceador de carga (a maioria dos quais pode lidar com isso sem qualquer tempo de inatividade).

O meu conselho é usar rsync com versões explodiram, mas implantar um arquivo de guerra.

  1. Criar pasta temporária no ambiente ao vivo, onde você vai ter versão do webapp explodiu.
  2. Rsync explodiu versões.
  3. Depois successfull rsync criar um arquivo de guerra na pasta temporária na máquina ambiente ao vivo.
  4. Substitua velha guerra no diretório deploy servidor com novo a partir de pasta temporária.

Substituir guerra antigo com o novo é recomendado no recipiente JBoss (que é baseado em Tomcat) beacause it'a operação atômica e rápido e é certeza de que quando deployer começará aplicativo inteiro estará no estado implantado.

Você não pode fazer uma cópia local da aplicação web atual no servidor web, rsync para esse diretório e, em seguida, talvez até mesmo usando links simbólicos, em um "ir", ponto Tomcat para uma nova implantação, sem muito tempo de inatividade?

A sua abordagem ao rsync a guerra extraído é boa bonita, também o reinício pois acredito que um servidor de produção não deve ter hot-implantação habilitado. Então, a única desvantagem é o tempo de inatividade quando você precisa reiniciar o servidor, certo?

Eu assumo todo o estado de sua aplicação está detido na base de dados, para que você não tem nenhum problema com alguns usuários trabalhando em instância do servidor de um aplicativo enquanto outros usuários estão em outra instância do servidor de aplicativos. Se assim for,

Executar dois servidores de aplicação : Iniciar-se o segundo servidor de aplicações (o que escuta em outras portas TCP) e implantar seu aplicativo lá. Após a implantação, atualizar a configuração do Apache httpd (mod_jk ou mod_proxy) para apontar para o segundo servidor de aplicativos. Graciosa reiniciar o processo httpd Apache. Desta forma, você não terá tempo de inatividade e os novos usuários e pedidos são automaticamente redirecionados para o novo servidor de aplicações.

Se você pode fazer uso de suporte de replicação de agrupamento e de sessão do servidor de aplicativo, ele será ainda suave para os usuários que estão conectados no momento, como o segundo servidor de aplicativo irá sincronizar novamente assim que começa. Então, quando não há acessos para o primeiro servidor, desligue-o.

Esta é dependente de sua arquitetura de aplicação.

Uma das minhas aplicações senta atrás de um proxy de balanceamento de carga, onde eu executar uma implantação escalonada -. Efetivamente erradicar o tempo de inatividade

Se os arquivos estáticos são uma grande parte do seu grande WAR (100Mo é muito grande), em seguida, colocá-los fora da guerra e implantá-los em um servidor web (por exemplo Apache) na frente de seu servidor de aplicativos pode acelerar as coisas. Em cima disso, o Apache geralmente faz um trabalho melhor em servir arquivos estáticos do que um motor de servlet faz (mesmo se a maioria deles feito progressos significativos nessa área).

Assim, em vez de produzir uma grande guerra de gordura, colocá-lo na dieta e produtos:

  • um grande ZIP gordura com arquivos estáticos para o Apache
  • um WAR menos gordura para o mecanismo de servlet.

Opcionalmente, ir mais longe no processo de fazer o mais fino WAR:. Se possível, implantar Grails e outros JARs que não mudam com freqüência (que é provavelmente o caso da maioria deles) no nível do servidor de aplicação

Se você tiver sucesso na produção de um WAR mais leve, eu não incômodo de rsyncing diretórios em vez de arquivos.

Pontos fortes desta abordagem:

  1. Os arquivos estáticos pode ser quente "implantado" no Apache (por exemplo, usar um link simbólico que aponta no diretório atual, descompacte os arquivos novos, atualizar o link simbólico e voilà).
  2. A guerra será mais fino e vai demorar menos tempo para implantá-lo.

A fraqueza desta abordagem:

  1. Há mais um servidor (o servidor web) para este complemento (um pouco) mais complexidade.
  2. Você precisará alterar os scripts de construção (não é um grande negócio IMO).
  3. Você precisará alterar a lógica rsync.

Eu não tenho certeza se isso responde sua pergunta, mas eu vou compartilhar sobre o processo de implantação Eu uso ou encontro nos poucos projectos que fiz.

Semelhante a você, eu não nunca lembro de fazer uma reafectação guerra total ou atualização. Na maioria das vezes, as minhas actualizações estão restritos a alguns arquivos jsp, talvez uma biblioteca, alguns arquivos de classe. Eu sou capaz de gerenciar e determinar quais são os artefatos afetados, e, geralmente, nós embalados aqueles atualização em um arquivo zip, juntamente com um script de atualização. Vou executar o script de atualização. O script faz o seguinte:

  • backup dos arquivos que serão substituídos, talvez para uma pasta com data e hora de hoje.
  • descompactar os meus arquivos
  • Parar o servidor de aplicativos
  • Mova os arquivos ao longo
  • Inicie o servidor de aplicativos

Se o tempo de inatividade é uma preocupação, e eles geralmente são, meus projetos são geralmente HA, mesmo se eles não estão compartilhando Estado, mas usando um roteador que fornece roteamento de sessão pegajoso.

Outra coisa que estou curioso seria, por isso a necessidade de rsync? Você deve ser capaz de saber quais são as mudanças necessárias, determinando-los em seu ambiente de teste / desenvolvimento, e não executar verificações delta com ao vivo. Na maioria dos casos, você tem que sintonizar o seu rsync para ignorar arquivos de qualquer maneira, como alguns arquivos de propriedade que definem recursos um uso servidor de produção, como conexão de banco de dados, servidor SMTP, etc.

Espero que isso é útil.

Em que é o seu conjunto PermSpace? Eu esperaria ver isso crescer tão bem, mas deve ir para baixo após a coleta das classes de idade? (Ou que o ClassLoader ainda sentar?)

Pensando outloud, você poderia rsync para um diretório Versão ou chamado data-separado. Se os suportes de contentores links simbólicos, você poderia SIGSTOP o processo raiz, mude raiz sistema de arquivos do contexto via link simbólico, e depois SIGCONT?

Quanto ao contexto reiniciado início. Todos os recipientes têm opções de configuração para desativar auto-redeploy no arquivo de classe ou alterações de recursos estáticos. Você provavelmente não pode desativar o Auto reimplementa sobre mudanças web.xml para que este arquivo é o último a atualização. Então, se você desativar a auto redeploy e atualizar o web.xml como o último que você verá o reinício contexto após toda a atualização.

carregar a nova versão do webapp para um diretório separado, então, ou mover-se para trocá-lo com a execução, ou usar links simbólicos. Por exemplo, temos um link simbólico no diretório webapps Tomcat chamado "myapp", que aponta para o webapp atual com o nome "myapp-1,23". Nós fazer o upload do novo webapp para "myapp-1,24". Quando tudo estiver pronto, pare o servidor, remova o link simbólico e fazer um novo apontando para a nova versão, em seguida, iniciar o servidor novamente.

disable auto-reload em servidores de produção para o desempenho, mas, mesmo assim, ter arquivos dentro do webapp mudando de uma forma não-atômica pode causar problemas, como arquivos estáticos ou mesmo páginas JSP poderia mudar de maneiras que causam links quebrados ou pior.

Na prática, os webapps estão realmente localizados em um dispositivo de armazenamento compartilhado, de modo agrupado, equilibrada de carga e servidores de failover, todos têm o mesmo código disponível.

A principal desvantagem para a sua situação é que o carregamento levará mais tempo, uma vez que o seu método permite rsync apenas para transferir arquivos modificados ou adicionados. Você pode copiar a pasta webapp antigo para o novo primeiro, e rsync que, se isso faz uma diferença significativa, e se é realmente um problema.

Tomcat 7 tem um recurso interessante chamado " implantação paralela " que é projetado para este caso de uso.

A essência é que você expandir o .war em um diretório, diretamente sob webapps / ou simbolicamente. sucessivas versões do aplicativo estão em diretórios nomeados app##version, por exemplo myapp##001 e myapp##002. Tomcat irá lidar com sessões existentes indo para a versão antiga, e novas sessões vão para a nova versão.

O problema é que você tem que ser muito cuidado com vazamentos PermGen. Isto é especialmente verdadeiro com Grails que usa um monte de PermGen. VisualVM é seu amigo.

Basta usar 2 ou mais tomcat servidores com um proxy sobre ele. Isso proxy pode ser de apache / nignix / haproxy.

Agora, em cada uma o servidor proxy não é "in" e "out" url com portas estão configuradas.

Em primeiro lugar copiar sua guerra no tomcat sem parando o serviço. Uma vez que a guerra é implantado é aberto automaticamente pelo motor tomcat.

unpackWARs Nota cruzar = "true" e autodeploy = "true" no nó "Host" dentro server.xml

É olhar gosta dessa

  <Host name="localhost"  appBase="webapps"
        unpackWARs="true" autoDeploy="true"
        xmlValidation="false" xmlNamespaceAware="false">

Agora veja os logs de tomcat. Se nenhum erro está lá isso significa que é com sucesso.

Agora bateu todos APIs para testar

Agora, vamos para o servidor proxy.

Simplesmente alterar o mapeamento fundo url com o nome da nova guerra. Desde registrar com os servidores proxy como apache / nignix / HAProxy levou muito menos tempo, você vai se sentir mínimo tempo de inatividade

Consulte - https://developers.google.com/speed/pagespeed/module / domínios para urls mapeamento

Você está usando Resin, Resin tem suporte embutido para aplicativos web versionamento.

http://www.caucho.com/resin-4.0/ admin / deploy.xtp # VersioningandGracefulUpgrades

Update:. É do processo watchdog pode ajudar com questões permgenspace demasiado

Não é um "melhor prática", mas algo que eu só pensava.

Como sobre a implantação do webapp através de um DVCS como git?

Desta forma, você pode deixar figura git quais arquivos para transferir para o servidor. Você também tem uma boa maneira de voltar com isso se ele sair para ser preso, basta fazer uma revert!

Eu escrevi um script que leva alguns parâmetros e rsyncs o arquivo entre servidores. Acelera a transferência rsync muito para arquivos maiores:

https://gist.github.com/3985742

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top