Como implantar um aplicativo ASP.NET com zero tempo de inatividade

127

Para implantar uma nova versão do nosso site, fazemos o seguinte:

  1. Feche o novo código e faça o upload para o servidor.
  2. No servidor ativo, exclua todo o código ativo do diretório de sites do IIS.
  3. Extraia o novo arquivo zip do código no diretório IIS agora vazio

Esse processo é todo roteirizado e acontece muito rapidamente, mas ainda pode haver um tempo de inatividade de 10 a 20 segundos quando os arquivos antigos estão sendo excluídos e os novos arquivos sendo implantados.

Alguma sugestão para um método de tempo de inatividade de 0 segundo?

Karl Glennon
fonte
Isso não deveria estar no ServerFault?
21711 Daniel Rodriguez
49
Talvez, mas o ServerFault não existisse em setembro '08
Karl Glennon
3
O IIS pode apontar para uma pasta de link simbólico? Alterar o link simbólico fará com que o processo do IIS seja reciclado?
Neil McGuigan
alguma solução final com amostra de script de código fonte completo?
Kiquenet 12/12/12
Não é possível ter vários pools de aplicativos e alternar o tráfego de um pool de aplicativos para outro?
Luke

Respostas:

79

Você precisa de 2 servidores e um balanceador de carga. Aqui estão as etapas:

  1. Ativar todo o tráfego no servidor 2
  2. Implantar no servidor 1
  3. Servidor de Teste 1
  4. Ligue todo o tráfego no servidor 1
  5. Implantar no servidor 2
  6. Servidor de Teste 2
  7. Ativar tráfego nos dois servidores

O fato é que, mesmo nesse caso, você ainda terá reinicializações de aplicativos e perda de sessões se estiver usando "sessões fixas". Se você tiver sessões de banco de dados ou um servidor de estado, tudo ficará bem.

Sklivvz
fonte
4
Você também pode configurar o balanceador de carga para que ele atenda às sessões existentes para um determinado servidor, mas não aceite novas. Isso permite que você evite interromper as sessões. Essa técnica, porém, requer aguardar o término das sessões e, em geral, você desejará criar um script.
35
Esse método tende a cair quando o rolo de código tem alterações estruturais no banco de dados. Depois de atualizar o banco de dados para o servidor 1, o servidor 2 explodirá. Agora você pode fazer backup / restaurar o banco de dados para teste no servidor 1, mas terá o problema de classificar os dados que foram alterados no banco de dados ativo enquanto a cópia paralela estava em execução.
Augarr
1
@AndreiRinea - como você acha que isso funcionaria em um sistema OLTP de alto volume? O sistema fica fora de sincronia e você perde dados quando recorta ou você precisa pausar a entrada de dados e escrever um script para identificar e migrar os dados transitórios para a nova estrutura de banco de dados.
EBarr
9
@EBarr: e, de qualquer forma, tecnicamente você ainda tem zero tempo de inatividade no aplicativo ASP.NET - a questão não é "como implantar em um servidor sql db com zero tempo de inatividade".
Sklivvz
6
A chave é desenvolver de uma maneira que suas alterações de sql não sejam destrutivas. Muitas vezes, é necessário fazer alterações destrutivas no sql no release a seguir, quando ele não for mais usado. Não é difícil fazer com a prática.
Bealer
60

A Microsoft Web Deployment Tool suporta isso até certo ponto:

Ativa o suporte ao sistema de arquivos transacionais do Windows (TxF). Quando o suporte a TxF está ativado, as operações de arquivo são atômicas; isto é, eles conseguem ou fracassam completamente. Isso garante a integridade dos dados e impede a existência de dados ou arquivos em um estado "meio caminho" ou corrompido. No MS Deploy, o TxF está desativado por padrão.

Parece que a transação é para toda a sincronização. Além disso, o TxF é um recurso do Windows Server 2008, portanto, esse recurso de transação não funcionará com versões anteriores.

Eu acredito que é possível modificar seu script para o tempo de inatividade 0 usando pastas como versões e a metabase do IIS:

  • para um caminho / URL existente:
  • Copie o novo site (ou modificado) para o servidor em
    • \ web \ app \ v2.1 \
  • Modifique a metabase do IIS para alterar o caminho do site
    • de \ web \ app \ 2.0 \
    • para \ web \ app \ v2.1 \

Este método oferece os seguintes benefícios:

  • Caso a nova versão tenha um problema, você poderá reverter facilmente para a v2.0
  • Para implantar em vários servidores físicos ou virtuais, você pode usar seu script para implantação de arquivos. Depois que todos os servidores tiverem a nova versão, você poderá alterar simultaneamente as metabases de todos os servidores usando a Microsoft Web Deployment Tool.
George Tsiokos
fonte
5
Implementei essa abordagem adaptando nossos scripts de implantação do PowerShell. Você pode ver a parte do script que altera a pasta do site do IIS aqui: stackoverflow.com/questions/330608/… Obrigado pelo ponteiro.
Karl Glennon
17
Infelizmente, esse método não leva em conta alterações estruturais no banco de dados. Depois de atualizar o DB para a v2.1, a v.2.0 explode.
EBarr
8
Usar TxF é um exagero aqui, IMO. Não custa nada ter as v2.0 e v2.1 no sistema de arquivos ao mesmo tempo. A grande mudança acontece quando a v2.1 fica on-line e, nesse momento, a transação TxF foi confirmada. O tempo de inatividade zero realmente acontece devido à maneira como o IIS se move de um antigo AppPool para um novo, não por causa do TxF.
RickNZ
5
Outro problema é se uma grande quantidade de dados do usuário é armazenada nas subpastas das pastas do aplicativo.
Kenny Evitt
4
Essa não é a implantação de 0 segundo, porque o novo aplicativo precisa ser iniciado.
usr
12

Você pode obter uma implantação de tempo de inatividade zero em um único servidor utilizando o Application Request Routing no IIS como um balanceador de carga de software entre dois sites IIS locais em portas diferentes. Isso é conhecido como uma estratégia de implantação verde azul, na qual apenas um dos dois sites está disponível no balanceador de carga a qualquer momento. Implante no site que está "inativo", aqueça-o e leve-o para o balanceador de carga (geralmente passando uma verificação de funcionamento do Application Request Routing) e, em seguida, retire o site original que estava ativo, fora do "pool" (novamente) fazendo sua verificação de integridade falhar).

Um tutorial completo pode ser encontrado aqui.

kavun
fonte
7

Eu passei por isso recentemente e a solução que encontrei foi ter dois sites configurados no IIS e alternar entre eles.

Para a minha configuração, eu tinha um diretório da web para cada site A e B assim: c: \ Intranet \ Live A \ Interface c: \ Intranet \ Live B \ Interface

No IIS, tenho dois sites idênticos (mesmas portas, autenticação etc), cada um com seu próprio pool de aplicativos. Um dos sites está em execução (A) e o outro está parado (B). o ao vivo também tem o cabeçalho do host ao vivo.

Quando se trata de implantar para viver, simplesmente publico no local do site STOPPED. Como posso acessar o site B usando sua porta, posso pré-aquecer o site para que o primeiro usuário não cause o início do aplicativo. Em seguida, usando um arquivo em lotes, copio o cabeçalho do host ativo para B, paro A e inicio B.

Rob King
fonte
1
Isso ajuda no tempo de inatividade devido à cópia do arquivo, mas tem o mesmo problema que o @Sklivvz - assim que o rolo de código tem alterações estruturais no banco de dados, o site cresce.
Augarr
Essa também parecia a maneira intuitiva para mim, mas por que não existe uma maneira fácil e integrada de fazer isso?
Petrus Theron
3
@ Ebarr, então, não implemente alterações destrutivas de sql. Por exemplo, se você precisar remover uma coluna, faça-o na próxima versão, quando ela não for mais usada por A ou B.
Bealer
@Bealer - concordou (com ressalva). Há uma série de perguntas sobre "tempo de inatividade durante funções de código". Ainda não encontrei um que realmente discuta as realidades da evolução de um esquema de banco de dados. Advertência - há uma variedade de complicações que acompanham alterações em duas fases do esquema. Um exemplo - muitos dos ORMs vomitam se a definição da tabela for diferente da definição como ela a entende (colunas novas ou ausentes).
EBarr
2
@Rob, como você pode "pré-aquecer" o site se ele estiver parado?
Andrew Gee
7

Usando a classe ServerManager do Microsoft.Web.Administration, você pode desenvolver seu próprio agente de implantação.

O truque é alterar o PhysicalPath do VirtualDirectory, que resulta em uma troca atômica on-line entre aplicativos da Web antigos e novos.

Esteja ciente de que isso pode resultar na execução de novos e antigos AppDomains em paralelo!

O problema é como sincronizar alterações nos bancos de dados etc.

Ao pesquisar a existência de AppDomains com PhysicalPaths antigos ou novos, é possível detectar quando os AppDomain antigos foram encerrados e se os novos AppDomain (s) foram iniciados.

Para forçar a inicialização de um AppDomain, você deve fazer uma solicitação HTTP (o IIS 7.5 suporta o recurso Autostart)

Agora você precisa de uma maneira de bloquear solicitações para o novo AppDomain. Eu uso um mutex nomeado - que é criado e de propriedade do agente de implantação, aguardado pelo Application_Start do novo aplicativo Web e, em seguida, liberado pelo agente de implantação após as atualizações do banco de dados.

(Uso um arquivo de marcador no aplicativo da web para ativar o comportamento de espera por mutex) Quando o novo aplicativo da web estiver em execução, excluo o arquivo do marcador.

Jack
fonte
6

OK, então como todo mundo está votando negativamente na resposta que escrevi em 2008 * ...

Vou lhe contar como fazemos isso agora em 2014. Não usamos mais sites porque estamos usando o ASP.NET MVC agora.

Certamente não precisamos de um balanceador de carga e dois servidores para isso, tudo bem se você tiver três servidores para cada site que você mantém, mas é um exagero total para a maioria dos sites.

Além disso, não confiamos no assistente mais recente da Microsoft - magia muito lenta e oculta demais e propensa a mudar seu nome.

Aqui está como fazemos:

  1. Temos uma etapa de pós-compilação que copia as DLLs geradas em uma pasta 'bin-pub'.

  2. Usamos o Beyond Compare (que é excelente **) para verificar e sincronizar arquivos alterados (por FTP, porque esse é amplamente suportado) até o servidor de produção

  3. Temos um URL seguro no site que contém um botão que copia tudo de 'bin-pub' para 'bin' (primeiro faça um backup para ativar a reversão rápida). Nesse ponto, o aplicativo é reiniciado. Em seguida, nosso ORM verifica se existem tabelas ou colunas que precisam ser adicionadas e as cria.

Isso é apenas milissegundos de inatividade. A reinicialização do aplicativo pode demorar um ou dois segundos, mas durante as solicitações de reinicialização são armazenadas em buffer, para que haja efetivamente zero tempo de inatividade.

Todo o processo de implantação leva de 5 segundos a 30 minutos, dependendo de quantos arquivos foram alterados e quantas alterações devem ser revisadas.

Dessa forma, você não precisa copiar um site inteiro para um diretório diferente, mas apenas para a pasta bin. Você também tem controle total sobre o processo e sabe exatamente o que está mudando.

** Sempre fazemos um rápido exame das mudanças que estamos implantando - como uma verificação dupla de última hora, para que saibamos o que testar e se algo quebrar, estamos prontos. Usamos o Beyond Compare porque permite que você diferencie facilmente os arquivos pelo FTP. Eu nunca faria isso sem o BC, você não tem idéia do que está substituindo.

* Role para baixo para vê-lo :( BTW, eu não recomendaria mais os sites porque eles são mais lentos de compilar e podem travar muito com os arquivos temporários compilados pela metade. Nós os usamos anteriormente porque permitiam arquivos mais ágeis por arquivo Muito rápido para corrigir um problema menor e você pode ver exatamente o que está implantando (se estiver usando o Beyond Compare, é claro - esqueça-o).

Mike Nelson
fonte
Mas você ainda terá tempo de inatividade porque o pool de aplicativos é reciclado.
testpattern
Não, sem tempo de inatividade porque os pedidos são armazenados automaticamente pelo IIS durante a reinicialização aplicativo
mike nelson
5

Os únicos métodos de tempo de inatividade zero em que posso pensar envolvem hospedagem em pelo menos 2 servidores.

Sam Meldrum
fonte
1

Eu refino a resposta de George um pouco, como segue, para um único servidor:

  1. Use um projeto de implantação da Web para pré-compilar o site em uma única DLL
  2. Feche o novo site e carregue-o no servidor
  3. Descompacte-o em uma nova pasta localizada em uma pasta com as permissões corretas para o site, para que os arquivos descompactados herdam as permissões corretamente (talvez e: \ web, com subpastas v20090901, v20090916, etc)
  4. Use o Gerenciador do IIS para alterar o nome da pasta que contém o site
  5. Mantenha a pasta antiga por um tempo, para que você possa usá-la em caso de problemas

A etapa 4 fará com que o processo de trabalho do IIS seja reciclado.

Isso é apenas zero tempo de inatividade se você não estiver usando sessões InProc; use o modo SQL, se puder (melhor ainda, evite o estado da sessão completamente).

Claro, é um pouco mais envolvido quando há vários servidores e / ou alterações no banco de dados ....

RickNZ
fonte
1
Mesmo problema que @Sklivvz - esse método cai assim que o rolo de código tem alterações estruturais no banco de dados.
Augarr
3
Foi por isso que eu disse que estava mais envolvido quando há alterações no banco de dados ... A distribuição de código com alterações estruturais no banco de dados não é apenas um problema de implantação; também deve haver suporte no código e provavelmente no banco de dados também.
RickNZ
1

Para expandir a resposta do sklivvz, que contava com algum tipo de balanceador de carga (ou apenas uma cópia em espera no mesmo servidor)

  1. Direcionar todo o tráfego para o Site / Servidor 2
  2. Opcionalmente, aguarde um pouco para garantir que o menor número possível de usuários possua fluxos de trabalho pendentes na versão implantada
  3. Implante no Site / Servidor 1 e aqueça o máximo possível
  4. Executar migrações de banco de dados de maneira transacional (procure tornar isso possível)
  5. Direcione imediatamente todo o tráfego para o Site / Servidor 1
  6. Implantar no site / servidor 2
  7. Tráfego direto para sites / servidores

É possível introduzir um pouco de teste de fumaça, criando uma captura instantânea / cópia do banco de dados, mas isso nem sempre é viável.

Se possível e necessário, use "diferenças de roteamento", como URL diferente do inquilino: s (customerX.myapp.net) ou usuários diferentes, para implantar primeiro um grupo desconhecido de cobaias. Se nada falhar, libere para todos.

Como as migrações de banco de dados estão envolvidas, a reversão para uma versão anterior geralmente é impossível.

Existem maneiras de tornar os aplicativos mais agradáveis ​​nesses cenários, como o uso de filas de eventos e mecanismos de reprodução, mas como estamos falando sobre a implantação de alterações em algo que está em uso, não há realmente nenhuma maneira à prova de idiotas.

gliljas
fonte
1

É assim que eu faço:

Requisitos mínimos absolutos do sistema:
1 servidor com

  • 1 balanceador de carga / proxy reverso (por exemplo, nginx) em execução na porta 80
  • 2 chroot-jails ou containers docker do ASP.NET-Core / mono-proxy reverso / fastcgi ou containers docker escutando 2 portas TCP diferentes
    (ou até apenas dois aplicativos de proxy reverso em 2 portas TCP diferentes, sem qualquer sandbox)

Fluxo de trabalho:

iniciar transação myupdate

try
    Web-Service: Tell all applications on all web-servers to go into primary read-only mode 
    Application switch to primary read-only mode, and responds 
    Web sockets begin notifying all clients 
    Wait for all applications to respond

    wait (custom short interval)

    Web-Service: Tell all applications on all web-servers to go into secondary read-only mode 
    Application switch to secondary read-only mode (data-entry fuse)
    Updatedb - secondary read-only mode (switches database to read-only)

    Web-Service: Create backup of database 
    Web-Service: Restore backup to new database
    Web-Service: Update new database with new schema 

    Deploy new application to apt-repository 
    (for windows, you will have to write your own custom deployment web-service)
    ssh into every machine in array_of_new_webapps
    run apt-get update
    then either 
    apt-get dist-upgrade
    OR
    apt-get install <packagename>
    OR 
    apt-get install --only-upgrade <packagename>
    depending on what you need
    -- This deploys the new application to all new chroots (or servers/VMs)

    Test: Test new application under test.domain.xxx
    -- everything that fails should throw an exception here
    commit myupdate;

    Web-Service: Tell all applications to send web-socket request to reload the pages to all clients at time x (+/- random number)
    @client: notify of reload and that this causes loss of unsafed data, with option to abort 

    @ time x:  Switch load balancer from array_of_old_webapps to array_of_new_webapps 
    Decomission/Recycle array_of_old_webapps, etc.

catch
        rollback myupdate 
        switch to read-write mode
        Web-Service: Tell all applications to send web-socket request to unblock read-only mode
end try 
Stefan Steiger
fonte
-7

Eu sugeriria manter os arquivos antigos lá e simplesmente substituí-los. Dessa forma, o tempo de inatividade é limitado aos tempos de substituição de arquivo único e há apenas um arquivo ausente por vez.

Não tenho certeza se isso ajuda em um "aplicativo da web" (acho que você está dizendo que é isso que está usando), e é por isso que sempre usamos "sites". Além disso, a implantação de "sites" não reinicia o site e descarta todas as sessões do usuário.

Mike Nelson
fonte
Olá Mike, convém remover esta resposta.
Sohail Ahmed