Atualizando um aplicativo Web sem tempo de inatividade

31

É um aplicativo PHP. Como posso minimizar o tempo de inatividade ao atualizar toda a base de código?

Simon Hayter
fonte

Respostas:

44

O que geralmente fazemos no trabalho é:

  • Antes de atualizar, a raiz do documento do servidor é:
    • em /www/app-2009-09-01
    • mas é acessado através de um link simbólico, chamado /www/application
  • colocamos toda a nova base de código em /www/app-2009-09-08
  • quando toda a base de código estiver lá:
    • removemos o antigo link simbólico
    • criamos um novo link simbólico, ainda chamado /www/application, mas que aponta para as novas fontes:/www/app-2009-09-08
  • recarregamos o apache para forçar a modificação a ser levada em consideração.

Todo esse processo é feito através de um script automático (a única coisa não automática é lançá-lo quando necessário). Isso significa :

  • Tudo passa rápido (especialmente a troca de link simbólico, que é a parte importante)
  • Não há risco de cometer um erro: o script foi bem testado e está funcionando há meses / anos


Outra vantagem dessa precedência de link simbólico é que é muito fácil "reverter" uma atualização se notarmos um erro catastrófico somente após colocar a nova versão das fontes em produção: basta mudar os links simbólicos.

Obviamente, isso não impede que você teste a nova versão em seu servidor intermediário antes de colocá-la em produção - mas, quem sabe ... Às vezes, há um bug muito grande que ninguém conseguiu ver enquanto testing :-(
Por exemplo, porque não há testes de carga realizados regularmente na máquina de preparo
(vi a coisa de "reversão" usada algo como 4 ou 5 vezes em 3 anos - a cada vez, salvou o dia - e os sites ^^)


Aqui está um exemplo rápido: suponha que eu tenha esse VirtualHost na minha configuração do Apache:

<VirtualHost *>
        ServerName example.com
        DocumentRoot /www/application
        <Directory /www/application>
            # Whatever you might need here (this example is copy-pasted from a test server and test application ^^ )
            Options Indexes FollowSymLinks MultiViews +SymLinksIfOwnerMatch
            AllowOverride All
            php_value   error_reporting 6135
            php_value short_open_tag  on
        </Directory>
</VirtualHost>

Bastante "padrão" ... A única coisa é que /www/applicationnão é um diretório real: é apenas um link simbólico para a versão atual das fontes.
O que significa que quando você colocar as fontes no servidor, mas ainda não tiver alternado, terá algo parecido com isto:

root@shark:/www
# ll
total 8
drwxr-xr-x 2 root root 4096 2009-09-08 22:07 app-2009-09-01
drwxr-xr-x 2 root root 4096 2009-09-08 22:07 app-2009-09-08
lrwxrwxrwx 1 root root   19 2009-09-08 22:08 application -> /www/app-2009-09-01

Observe que o symlinc aponta para a "versão antiga"

Agora, que a nova versão foi totalmente carregada no servidor, vamos mudar:

root@shark:/www
# rm /www/application
root@shark:/www
# ln -s /www/app-2009-09-08 /www/application

E, agora, os /www/applicationpontos para a nova versão das fontes:

root@shark:/www
# ll
total 8
drwxr-xr-x 2 root root 4096 2009-09-08 22:07 app-2009-09-01
drwxr-xr-x 2 root root 4096 2009-09-08 22:07 app-2009-09-08
lrwxrwxrwx 1 root root   19 2009-09-08 22:09 application -> /www/app-2009-09-08

E nós apenas temos que reiniciar o Apache:

root@shark:/www
# /etc/init.d/apache2 restart
 * Restarting web server apache2

As três etapas " remova o link; crie o novo link; reinicie o apache " devem ser feitas rapidamente; isto é, por um script automatizado, e não por um ser humano.

Usando esta solução:

  • você pode levar o tempo necessário para fazer o upload da nova versão das fontes: o apache não as usará enquanto o symlic não tiver sido alterado
  • quando estiver tudo bem, mude o link simbólico: ele será mais rápido do que alterar 1 ou 2 arquivos ... O que significa praticamente nenhum tempo de inatividade :-)

E se usar algum cache de código de operação como APC com a opção stat em 0, isso pode significar ainda menos risco de tempo de inatividade, suponho.


Obviamente, esta é a versão "simples" - se você tiver alguns arquivos enviados, por exemplo, precisará usar outro link simbólico em algum lugar, ou outro VirtualHost ou o que for ...


Espero que isso seja mais claro :-)

Pascal MARTIN
fonte
É um tipo de troca de servidor também. :-)
Wim ten Brink
mod_rewrite para gerenciar links simbólicos?
@gAMBOOKa: no: apenas uma questão do DocumentRoot do Apache (ou VirtualHost DocumentRoot), que é / www / application ;; ou seja, o link simbólico - não importa para onde ele apontar.
2
Ótima resposta. Mais uma dica: você pode fazer o link simbólico ocorrer sem desvinculá-lo. Como citado: "Os três passos ... devem ser feitos rapidamente; isto é, por um script automatizado, e não por um ser humano". O comando mv é uma operação atômica, portanto, você pode criar um link simbólico como 'ln -s / www / app-2011-01-28 / www / application-temp' e, em seguida, executar um 'mv -T / www / application-temp / www / application '.
1
Há algo que não foi coberto pelo método de link simbólico. Seu caminho funciona com o Apache + mod_php, mas pode falhar no lighttpd + fastcgi. Em um site de alto tráfego, a solicitação será atendida no meio da troca do link que, a dependência do código php falhará com a versão mista.
Dennis C
2

Você não pode pegar o código existente e migrar o projeto para um arquivo php de teste separado, e usá-lo enquanto faz suas atualizações? O que quero dizer é que você deve ter um servidor de teste e um servidor de produção para que, quando precisar fazer uma atualização, não ocorra nenhum tempo de inatividade.

Comunidade
fonte
1

Configure um segundo servidor com a base de código atualizada e troque-o o mais rápido possível. :-)

Se não for possível, verifique se a sua base de código está dividida em dezenas de partes menores. Em seguida, o tempo de inatividade seria limitado a apenas uma subparte uma por vez. Os bloqueios de código menores são mais fáceis de substituir e a maioria continuará funcionando sem problemas. Apenas tente isso em um ambiente de teste primeiro!

Wim ten Brink
fonte
Como o aplicativo não foi testado com módulos fragmentados, pode resultar em cenários inesperados.
O que significa que isso estaria na sua lista de tarefas a seguir após esta atualização. :-) Torne-o mais modular e você pode atualizar por módulo.
Wim ten Brink
1
Isso está na lista de tarefas, mas é um objetivo de longo prazo. Como somos uma startup jovem, a organização da equipe de desenvolvimento levará um tempo. = D
1

Primeiro, eu frequentemente uso e gosto de um método semelhante à resposta de Pascal MARTIN.

Outro método que eu também gosto é usar meu SCM para enviar novos códigos. O processo exato depende do seu tipo de SCM (git vs svn vs ...). Se você estiver usando svn, eu gosto de criar uma ramificação "online" ou "produção" que faça checkout como raiz do documento no servidor. Então, sempre que eu quiser enviar um novo código de outra ramificação / tag / tronco, apenas submeto o novo código na ramificação "online" e execute o svn update na raiz do documento. Isso permite reversões muito fáceis, pois há um log de revisão completo do que foi subido / descido para o servidor e quem fez e quando. Você também pode executar facilmente essa ramificação "online" em uma caixa de teste, permitindo verificar o aplicativo que está prestes a enviar.

O processo é semelhante para o git e outros estilos de SCM, apenas modificado para ser mais natural para o estilo de fluxo de trabalho.

Deseja receber / pesquisar em vez de enviar atualizações? Basta ter um trabalho cron ou outro mecanismo mais inteligente, executar automaticamente o svn update.

Extra: você também pode usar esse processo para fazer backup de arquivos que seu aplicativo gravou no disco. Apenas tenha um trabalho cron ou algum outro mecanismo execute svn commit. Agora, os arquivos criados por seu aplicativo são armazenados em backup no SCM, na revisão registrada etc. (por exemplo, se um usuário atualiza um arquivo no disco, mas deseja que você o reverta, basta pressionar a revisão antiga).


fonte
0

Também uso uma abordagem semelhante à de Pascal MARTIN. Mas, em vez de carregar várias versões do meu aplicativo no servidor de produção, mantenho as "construções" atrás do meu firewall, cada uma em um diretório separado com o número e a data da construção. Quando quero fazer upload de uma nova versão, uso um script simples que inclui "rsync -avh --delay-updates". O sinalizador "delay = updates" fará o upload de tudo (diferente) para uma pasta temporária até que todas as atualizações estejam lá e depois mova tudo de uma só vez no final da transferência para os caminhos adequados, para que o aplicativo nunca esteja em um estado meio-velho-meio-novo. Ele tem o mesmo efeito que o método acima, exceto que eu apenas mantenho uma versão do aplicativo no site de produção (é melhor ter apenas os arquivos essenciais básicos no servidor de produção, IMO).


fonte