Elimine o tempo de inatividade por meio de atualizações de serviço com controle de versão

Historicamente, os administradores precisavam colocar um servidor offline para atualizar o software local. No entanto, o tempo de inatividade não é a solução em serviços globais 24 horas por dia×, 7 dias por semana. Usuários têm forte dependência de muitos serviços de nuvem modernos para administrar os negócios. Não existe um momento ideal para desativar um sistema, então como uma equipe pode fornecer serviço contínuo e instalar atualizações importantes de segurança e recursos?

Além de usar atualizações com controle de versão, esses serviços essenciais podem ser transferidos perfeitamente de uma versão para outra enquanto os clientes os usam ativamente. Nem todas as atualizações são difíceis. É fácil atualizar layouts ou estilos de front-end. Pode ser complexo fazer alterações em recursos, mas há práticas bem conhecidas para reduzir os riscos de migração. No entanto, as alterações que emanam da camada de dados apresentam uma nova classe de desafios que exigem consideração especial.

Atualizar camadas separadamente

Com um serviço online distribuído em vários datacenters e armazenamento de dados separado, nem tudo pode ser alterado simultaneamente. Se o serviço típico for dividido em código de aplicativo e bancos de dados, que supostamente têm controle de versão de forma independente entre si, um desses lados precisará absorver a complexidade de lidar com o controle de versão.

Muitas vezes, o controle de versão é mais fácil de manipular no código do aplicativo. Sistemas maiores em geral têm um pouco de código herdado, como o SQL que vive dentro dos bancos de dados. Em vez de complicar ainda mais esse SQL, o código do aplicativo deve lidar com a complexidade. Especificamente, você pode criar um conjunto de classes de fábrica que entendem o controle de versão SQL.

Durante cada sprint, crie uma nova interface com essa versão para que sempre exista código que corresponda a cada versão do banco de dados. Você pode facilmente reverter binários durante a implantação. Se algo der errado após a implantação dos novos binários, reverta para o código anterior. Se a implantação binária for bem-sucedida, inicie a manutenção do banco de dados.

Então, como isso realmente funciona? Por exemplo, suponha que sua equipe esteja implantando a Sprint 123 no momento. Os binários entendem o esquema do banco de dados da Sprint 123 e entendem o esquema da Sprint 122. O padrão geral é trabalhar com ambas as versões/sprints N e N-1 do esquema SQL. Os binários consultam o banco de dados, determinam com qual versão do esquema estão falando e carregam a associação apropriada. O código do aplicativo trata o caso quando o novo esquema de dados ainda não está disponível. Depois que a nova versão estiver disponível, o código do aplicativo poderá começar a usar a nova funcionalidade habilitada pela versão mais recente do banco de dados.

Avançar apenas com a camada de dados

Após a atualização dos bancos de dados, o serviço estará em uma situação de roll-forward se ocorrer um problema. As migrações de banco de dados on-line são complexas e, muitas vezes, de várias etapas. Portanto, o roll-forward costuma ser a melhor maneira de resolver um problema. Em outras palavras, se a atualização falhar, a reversão provavelmente também falhará. Há pouco valor em investir no esforço para criar e testar código de reversão que sua equipe nunca espera usar.

Sequência de implantação

Considere um cenário em que você precisa adicionar um conjunto de colunas a um banco de dados e transformar alguns dados. Essa transição precisa ser invisível para os usuários, o que significa evitar ao máximo os bloqueios de mesa e, depois, manter os bloqueios pelo menor tempo possível para que eles não sejam perceptíveis.

A primeira coisa que fazemos é manipular os dados, possivelmente em tabelas paralelas usando um gatilho SQL para manter os dados sincronizados. Grandes migrações e transformações de dados às vezes precisam ser de várias etapas em várias implantações em vários sprints.

Depois que os dados extras ou o novo esquema tiver sido criado em paralelo, a equipe entrará no modo de implantação para o código do aplicativo. No modo de implantação, quando o código faz uma chamada para o banco de dados, ele primeiro obtém um bloqueio no esquema e, depois, o libera após executar o procedimento armazenado. O banco de dados não pode ser alterado entre o momento em que a chamada para o banco de dados é emitida e quando o procedimento armazenado é executado.

O código de atualização atua como um gravador de esquema e solicita um bloqueio de gravador no esquema. O código do aplicativo tem prioridade na obtenção de um bloqueio de leitor, e o código de atualização fica em segundo plano tentando adquirir o bloqueio de gravador. Sob o bloqueio do gravador, apenas um pequeno número de operações muito rápidas são permitidas nas tabelas. O bloqueio é liberado e o aplicativo registra que a nova versão do banco de dados está em uso e utiliza a interface que corresponde à nova versão do banco de dados.

As atualizações do banco de dados são todas executadas por meio de um padrão de migração. Um conjunto de códigos e scripts examina a versão do banco de dados e, depois, faz alterações incrementais para migrar o esquema da versão antiga para a nova. Todas as migrações são automatizadas e implementadas por meio do serviço de gerenciamento de versões.

A interface do usuário da Web também deve ser atualizada sem interromper os usuários. Ao atualizar arquivos JavaScript, folhas de estilo ou imagens, evite misturar versões antigas e novas carregadas pelo cliente. Isso pode levar a erros que podem perder o trabalho em andamento, como um campo editado por um usuário. Portanto, você deve criar a versão de todos os arquivos JavaScript, CSS e de imagem colocando todos os arquivos associados a uma implantação em uma pasta separada com controle de versão. Quando a interface do usuário da Web faz chamadas para a camada de aplicativo, os ativos com uma versão especificada são carregados. Somente quando uma ação do usuário resulta em uma atualização de página inteira é que a nova interface do usuário da Web é carregada no navegador. A experiência do usuário não é interrompida pela atualização.

Próximas etapas

A Microsoft é uma das maiores empresas de desenvolvimento de software do mundo há décadas. Saiba como a Microsoft opera sistemas confiáveis com o DevOps.