Atingir Zero Downtime Deployment abordou o mesmo problema, mas preciso de alguns conselhos sobre uma estratégia que estou considerando.
Contexto
Um aplicativo baseado na Web com Apache / PHP para processamento no servidor e sistema de arquivos / banco de dados MySQL para persistência.
Atualmente, estamos construindo a infraestrutura. Todo o hardware de rede terá redundância e todos os cabos principais da rede serão usados em pares ligados para tolerância a falhas. Os servidores estão sendo configurados como pares de alta disponibilidade para tolerância a falhas de hardware e terão balanceamento de carga para tolerância a falhas de máquina virtual e desempenho geral.
É minha intenção que possamos aplicar atualizações ao aplicativo sem nenhum tempo de inatividade. Fiz um grande esforço ao projetar a infraestrutura para garantir que eu possa fornecer 100% de tempo de atividade; seria extremamente decepcionante ter 10 a 15 minutos de inatividade toda vez que uma atualização fosse aplicada. Isso é particularmente significativo, pois pretendemos ter um ciclo de lançamento muito rápido (às vezes, pode atingir um ou mais lançamentos por dia.
Topologia de rede
Este é um resumo da rede:
Load Balancer
|----------------------------|
/ / \ \
/ / \ \
| Web Server | DB Server | Web Server | DB Server |
|-------------------------|-------------------------|
| Host-1 | Host-2 | Host-1 | Host-2 |
|-------------------------|-------------------------|
Node A \ / Node B
| / |
| / \ |
|---------------------| |---------------------|
Switch 1 Switch 2
And onward to VRRP enabled routers and the internet
Nota: os servidores de banco de dados usam replicação master-master
Estratégia sugerida
Para conseguir isso, atualmente estou pensando em dividir os scripts de atualização do esquema do DB em duas partes. A atualização seria assim:
- O servidor da Web no nó A é retirado da rede; o tráfego continua sendo processado pelo servidor da web no nó B.
- Alterações de esquema de transição são aplicadas aos servidores de banco de dados
- Servidor da Web Uma base de código é atualizada, os caches são limpos e quaisquer outras ações de atualização são executadas.
- O servidor Web A é colocado online e o servidor B é colocado offline.
- A base de código do servidor Web B é atualizada, os caches são limpos e quaisquer outras ações de atualização são executadas.
- O servidor da Web B é colocado online.
- Alterações finais do esquema são aplicadas ao banco de dados
'Esquema de transição' seria projetado para estabelecer um banco de dados compatível com a versão cruzada. Isso usaria principalmente visualizações de tabela que simulam o esquema da versão antiga, enquanto a própria tabela seria alterada para o novo esquema. Isso permite que a versão antiga interaja com o banco de dados normalmente. Os nomes das tabelas incluiriam números de versão do esquema para garantir que não haja confusão sobre em qual tabela gravar.
'Esquema final' removeria a compatibilidade com versões anteriores e arrumaria o esquema.
Questão
Em suma, isso vai funcionar?
mais especificamente:
Haverá problemas devido ao potencial de gravações simultâneas no ponto específico da mudança de esquema de transição? Existe uma maneira de garantir que o grupo de consultas que modifica a tabela e cria a exibição compatível com versões anteriores seja executado consecutivamente? ou seja, com outras consultas sendo mantidas no buffer até que as alterações no esquema sejam concluídas, o que geralmente será de apenas milissegundos.
Existem métodos mais simples que fornecem esse grau de estabilidade e também permitem atualizações sem tempo de inatividade? Também é preferível evitar a estratégia de esquema "evolucionária", pois não desejo ficar preso à compatibilidade de esquemas com versões anteriores.
fonte
Sua estratégia é sólida. Eu ofereceria apenas considerar a possibilidade de expandir o "Esquema de transição" em um conjunto completo de "tabelas de transações".
Com tabelas de transações, os SELECTs (consultas) são executados em relação às tabelas normalizadas para garantir a correção. Mas todos os INSERTs, UPDATEs e DELETEs do banco de dados são sempre gravados nas tabelas de transações desnormalizadas.
Em seguida, um processo simultâneo separado aplica essas alterações (talvez usando Procedimentos armazenados) às tabelas normalizadas de acordo com as regras de negócios e os requisitos de esquema estabelecidos.
Na maioria das vezes, isso seria praticamente instantâneo. Mas a separação das ações permite que o sistema acomode atrasos excessivos de atividade e atualização de esquema.
Durante as alterações de esquema no banco de dados (B), as atualizações de dados no banco de dados ativo (A) entrariam em suas tabelas de transações e seriam imediatamente aplicadas a suas tabelas normalizadas.
Ao recuperar o banco de dados (B), as transações de (A) seriam aplicadas a ele, gravando-as nas tabelas de transação de (B). Depois que essa parte estiver concluída, (A) poderá ser desativado e o esquema será alterado. (B) terminaria de aplicar as transações de (A) e, ao mesmo tempo, manipularia suas transações ativas, que seriam colocadas na fila exatamente como (A) e as "operações ativas" seriam aplicadas da mesma maneira quando (A) retornasse.
Uma linha da tabela de transações pode parecer algo como ...
As "tabelas" da transação podem realmente ser linhas em um banco de dados NoSQL separado ou até arquivos seqüenciais, dependendo dos requisitos de desempenho. Um bônus é que a codificação do aplicativo (site, neste caso) fica um pouco mais simples, pois grava apenas nas tabelas de transações.
A idéia segue os mesmos princípios da contabilidade de dupla entrada e por razões semelhantes.
As tabelas de transações são análogas a um "diário" da contabilidade. As tabelas totalmente normalizadas são análogas a um "razão" de contabilidade, sendo que cada tabela é um pouco como uma "conta" de contabilidade.
Na contabilidade, cada transação recebe duas entradas no diário. Um para a conta contábil "debitada" e outro para a conta "creditada".
Em um RDBMS, um "diário" (tabela de transações) obtém uma entrada para cada tabela normalizada a ser alterada por essa transação.
A coluna DB na ilustração da tabela acima indica em qual banco de dados a transação se originou, permitindo que as linhas enfileiradas do outro banco de dados sejam filtradas e não reaplicadas quando o segundo banco de dados for recuperado.
fonte