Na empresa em que trabalho, usamos uma configuração simples de uma replicação primária-secundária. Se o Primário quebrar por qualquer motivo, fazemos a troca manualmente. Isso também significa que o MySQL quase nunca é atualizado. Eu quero tornar isso possível, atualizar os servidores sem tempo de inatividade. Por várias razões, não queremos uma solução (sobre)complicada. Então eu estou querendo saber, para atingir meu objetivo, pode ser tão simples assim:
Uma replicação primária-primária com replicação semi-síncrona e habilitada para GTID. Pacemaker para alternar um IP virtual de um servidor para outro, para que eu possa interromper a atualização de um servidor. Em seguida, volte e atualize o outro servidor.
Para a replicação primária-primária, não tenho o incremento automático configurado de forma diferente. Todos os processos de gravação usariam o IP virtual do marcapasso e, portanto, gravariam em apenas um host.
Fazemos isso na minha empresa. Executamos milhares de pares mestre-mestre do MySQL que usam esse método. Desenvolvemos um serviço que realiza a troca que você descreve. Chamamos isso de "sucesso" porque isso tem uma conotação mais positiva do que o failover. Podemos e fazemos isso a qualquer hora do dia, mesmo sem notificar a equipe do aplicativo que estamos fazendo isso.
Aqui estão os passos gerais:
Presumir:
"Master1" é a instância mestre gravável atual do MySQL, onde o VIP é definido.
"Master2" é uma réplica, em modo somente leitura.
Quando é automatizado, isso resulta em menos de um segundo de tempo de inatividade, desde que não haja um atraso significativo na replicação. Mover um VIP é muito mais rápido do que atualizar o DNS.
Em seguida, os aplicativos devem se reconectar ao VIP e, assim, obter acesso à nova instância primária e executar novamente as consultas necessárias.
Obviamente, os aplicativos não devem usar a instância MySQL em espera, porque o objetivo é permitir que ela seja colocada offline para atualizações, alterações de configuração, etc. Isso também oferece uma maneira rápida de responder se houver um problema com o servidor host que o MySQL está executando sobre. Recebemos algumas falhas de host ou discos com falha por semana, então fazemos essa troca rapidamente para garantir que o aplicativo possa continuar.
É inevitável que isso cause um breve "blip" onde os aplicativos têm suas conexões interrompidas e precisam se reconectar, mas é uma interrupção mais breve do que qualquer outra solução. Ainda assim, os aplicativos precisam ser projetados para detectar uma conexão interrompida e reconectar. Nosso maior problema é educar os desenvolvedores de aplicativos para fazer isso. Eles continuam reclamando que são alertados por uma conexão perdida, e nós dizemos a eles: "já documentamos o que você precisa fazer - não deve alertar por um único sinal".
Este sistema funciona há vários anos, mas agora temos um ambiente misto onde temos muitas instâncias MySQL na nuvem. Precisamos de uma nova solução, pois não podemos criar VIPs usando BGP na nuvem.
Então nós criamos um protótipo usando o Envoy como um proxy para o MySQL. Acreditamos que isso funcione, mas precisamos desenvolver um serviço para notificar o proxy Envoy sobre a mudança quando fizermos um sucessor. O Envoy suporta o protocolo GRPC, para que possamos enviar uma mensagem dinamicamente e ele começará a rotear o tráfego para uma instância de destino diferente do MySQL. Essa solução baseada em proxy deve funcionar de forma idêntica na nuvem e no datacenter. Mas esta solução é provavelmente mais trabalhosa do que você tinha em mente.
Também poderíamos usar o ProxySQL para fazer algo semelhante, mas o Envoy já tem muita adoção em nossa empresa para tráfego de serviço a serviço, portanto, se pudermos aproveitar isso, em vez de um novo tipo de proxy, teremos uma tecnologia a menos para usar.
Atualizar comentários:
A etapa 4 na lista acima aguarda a replicação ser atualizada enquanto ambas as instâncias são somente leitura. Portanto, não há novas atualizações permitidas em Master1 durante esse período, e Master2 só precisa executar um conjunto de atualizações restantes que foram confirmadas antes de Master1 ser definido como somente leitura. Felizmente, esta é uma espera muito breve, a menos que o Master2 já estivesse muito atrasado.
O serviço que executa o sucessor se recusa a iniciar a operação se detectar que o Master2 tem um atraso de replicação alto. O usuário é encorajado a tentar novamente mais tarde.
É claro que, no mundo real, às vezes você precisa substituir esse tipo de restrição por causa de circunstâncias urgentes, então há uma opção para forçar o sucessor. Mas isso vem com um risco, porque se você tornar o Master2 o principal e começar a permitir novas consultas diretamente nele, enquanto ainda houver atualizações pendentes para processar devido ao atraso na replicação, você acabará em uma situação de cérebro dividido: você pode fazer um update que será então substituído por um evento do log binário que realmente ocorreu no passado.
Então, em teoria, você pode habilitar o VIP no Master2, mas deixar o Master2 somente leitura até que ele alcance totalmente a replicação. Isso pelo menos executa parte do sucessor e permite que os clientes leiam os dados, mas não os atualizem temporariamente. Isso pode ser aceitável para alguns aplicativos por um curto período de tempo, mas depende dos requisitos do aplicativo.
Na prática, nossa implementação de successover não faz esse modo somente leitura temporário. Nós apenas tentamos ser muito relutantes em usar a opção de sucesso forçado, porque um cérebro dividido é extremamente difícil de limpar (pode não ser possível). Preferimos tentar o sucessor quando não houver atraso na replicação.