Como determinar o mestre no mysql master-slave

17

Estou configurando a replicação de mestre-escravo do MySQL e estou tentando descobrir como lidar com a situação de failover em que promovo o escravo para mestre (no caso de o mestre cair).

Meu servidor de aplicativos precisa direcionar todas as gravações para o mestre atual, mas não posso usar a HA no nível do servidor entre o mestre e o escravo (pulsação, keepalived), pois os dois servidores db estão em sub-redes completamente diferentes em diferentes locais físicos.

Eu acho que isso é algo que eu preciso lidar no nível do aplicativo. Posso consultar os dois servidores e perguntar qual deles é um mestre e, em seguida, executar todas as consultas nesse servidor.

Existe uma consulta no MySQL para ver se o servidor atual é mestre em uma réplica mestre-escravo?

Ethan Hayon
fonte
Qual versão do MySQL você está usando ???
RolandoMySQLDBA
Esta é a saída mysqlServer version: 5.5.23 MySQL Community Server (GPL)
Ethan Hayon

Respostas:

13

@RolandoMySQLDBA respondeu à pergunta com precisão ... mas ele também apontou que sua solução era "rápida e suja".

E essa é uma afirmação muito verdadeira. :)

O que me preocupa aqui não é com essa resposta, mas é que a pergunta original parece fazer uma suposição incorreta:

Posso consultar os dois servidores e perguntar qual deles é um mestre e, em seguida, executar todas as consultas nesse servidor.

O problema é que, na replicação do MySQL, o mestre nunca está verdadeiramente ciente de que é o mestre.

O conceito de "promoção para dominar" não é realmente um conceito na replicação assíncrona do MySQL. "Promover" um servidor MySQL para a função principal é algo que acontece "externo a" servidores MySQL, em oposição a algo que acontece "interno a" servidores MySQL.

A "promoção para mestre" não é feita por nenhum tipo de provisionamento de servidor, porque, tecnicamente, todo servidor MySQL que possui o log binário ativado é um mestre, mesmo que nunca tenha um escravo. SHOW MASTER STATUSfunciona exatamente da mesma maneira e retorna exatamente o mesmo resultado, escravos ou não, e um mestre com 2 escravos não é mais ou menos mestre do que um mestre com 1 escravo ou 0 escravos. Da mesma forma, um mestre cujos escravos estão todos off-line ainda é um mestre, porque quando os escravos se conectam novamente, eles começam a replicar de onde pararam.

Em certo sentido, a única "conscientização" por parte de qualquer servidor não é se é um mestre, mas se é um escravo (ou "não").

É o que a solução de Rolando pergunta: "você é escravo?" Se a resposta for não, então a suposição é de que esse deve ser o mestre ... o qual ele também apontou como uma suposição defeituosa se STOP SLAVE;for emitida. Mas um escravo parado ainda é escravo, então "não um escravo" (a qualquer momento) não significa "ser um mestre".

Um teste semelhante poderia ser feito no suposto mestre:

SELECT COUNT(1) FROM information_schema.processlist
 WHERE user = 'the_username_used_by_the_slave';

ou

SELECT COUNT(1) FROM information_schema.processlist
 WHERE command = 'binlog dump';

Se o valor for zero, o encadeamento IO do escravo não está conectado. Esse teste tem um defeito semelhante, pois se o escravo for desconectado administrativamente, isolado ou falhar, ele não será conectado. Portanto, isso também não resolve nada.

Pior ainda (para qualquer um desses cenários), a "tabela" information_schema.processlist é uma tabela virtual que se materializa toda vez que é selecionada, e isso leva tempo e custa recursos. Quanto mais ocupado o servidor, mais ele custa, porque a atividade de cada encadeamento deve ser examinada.

Uma solução mais leve seria:

SELECT @@global.read_only;

Em um escravo, você pode / deve definir a variável global read_onlypara que usuários sem o SUPERprivilégio não possam gravá-la acidentalmente (e seu aplicativo não deve ter SUPER). Se você "promover" manualmente o escravo para a função principal, SET GLOBAL read_only = OFFhabilite as gravações. (A replicação sempre pode gravar no escravo, não importa como isso esteja definido).

Mas, ainda assim, acho que falta um ponto importante:

Eu proporia que o aplicativo não deveria tomar essa decisão heuristicamente em uma configuração mestre / escravo, e certamente não em uma conexão por conexão. O aplicativo deve usar uma opção de configuração rígida ou permanecer inconsciente e ter o destino da conexão com o banco de dados tratado por outra coisa.

Ou, no mínimo, o aplicativo nunca deve alternar até que o mestre falhe e nunca deve voltar sozinho.

Aqui está o porquê de eu dizer o seguinte: depois que a "decisão" é tomada - por quem quer que seja - para tornar outro servidor o mestre, o aplicativo não pode, por qualquer motivo, voltar ao mestre original, mesmo depois de ficar on-line , sem intervenção.

Digamos que você tenha atingido um bug e houve uma falha forçada por software; mysqld_safereinicia obedientemente mysqlde a recuperação de falhas do InnoDB é executada na perfeição. Mas isso leva alguns minutos.

Enquanto isso, o mestre está inativo, portanto, seu aplicativo mudou para o escravo. As transações foram criadas, pedidos feitos, fundos transferidos, comentários postados, blogs editados, independentemente do sistema.

Agora, o mestre original volta a ficar online.

Se seu aplicativo voltar ao mestre original, você estará em um mundo absoluto de dano, porque a próxima coisa que provavelmente acontecerá é que a replicação será interrompida devido a uma inconsistência, porque seu aplicativo alterou os dados no escravo nesse sentido. Tempo. Agora você tem dois servidores de banco de dados com dados inconsistentes que precisarão reconciliar manualmente. Se houver dólares, pontos ou créditos envolvidos, agora você tem saldos incompatíveis.

Portanto, é fundamental que o aplicativo não possa voltar ao mestre original sem a sua intervenção.

Espere, você acabou de encontrar o problema com este cenário como eu o descrevi? O mestre falhou, mas seu aplicativo não utilizará o escravo, porque acha que o escravo ainda é o escravo e não o mestre ... a information_schema.processlistconsulta no escravo ainda retornará diferente de zero, mesmo se o servidor mestre estiver desligado .

Portanto, não há muito sentido em o aplicativo descobrir algo, pois você precisará manualmente STOP SLAVEpara que esse teste seja útil.

Talvez uma abordagem melhor, se você deseja que o aplicativo possa alternar, seria configurar os servidores com replicação circular.

A replicação circular tem seus próprios problemas, mas desde que seu aplicativo sempre esteja sempre gravando em um servidor por vez, a maioria desses problemas se tornará não-problemas. Em outras palavras, ambas as máquinas são sempre e simultaneamente mestre e escravo, no sentido de replicação, mas sua aplicação, através de algum mecanismo, está sempre apontando apenas uma máquina por vez como o "mestre" no qual pode e deve escrever .

Você não pode implantar ferramentas de alta disponibilidade nos servidores MySQL devido à sua separação, mas pode implementá-las com o HAProxy em execução nos servidores de aplicativos. O aplicativo se conecta ao "MySQL" no host local, que não é MySQL, mas na verdade é HAProxy ... e encaminha a conexão TCP à máquina MySQL apropriada.

O HAProxy pode testar as conexões com os servidores MySQL e oferecer apenas tráfego para uma máquina MySQL que esteja aceitando conexões e permitindo autenticação.

A combinação do HAProxy em execução no servidor de aplicativos (sua demanda por recursos não será substancial em comparação com tudo o que o servidor de aplicativos tem que fazer - é praticamente unir soquetes e ignorar sua carga útil) ... e replicação circular do MySQL seria a abordagem que eu provavelmente adotaria neste caso, com base no que é conhecido da pergunta.

Ou, para uma configuração estritamente manual, opte por algo muito mais simples do que "descoberta", como uma entrada no /etc/hostsarquivo do servidor de aplicativos com um nome de host que o aplicativo usa para se conectar ao MySQL, que você pode atualizar manualmente - assumindo a promoção de escravo para master pretende ser um processo manual.

Ou, algo mais complexo, usando o Percona XtraDB Cluster. Para isso, no entanto, você deseja adicionar um terceiro servidor, porque com 3 nós no PXC, se 2 servidores puderem se ver, mas ficarem isolados de 1 servidor (se todos os três ainda estiverem em execução), os 2 servidores continuarão funcionando alegremente, mas o servidor 1 se enrola e se recusa a fazer qualquer coisa, pois percebe que deve ser o estranho. Isso funciona porque os 2 percebem que ainda constituem a maioria dos nós que estavam online antes da divisão da rede e o 1 percebe que não. Com o PXC, não importa realmente a qual servidor seu aplicativo se conecta.

Eu digo que tudo isso é para dizer "não faça com que o aplicativo faça uma pesquisa nos servidores para ver qual deles é o mestre", porque ele o morderá mais cedo ou mais tarde e diminuirá seu desempenho até o dia em que ele morder.

Michael - sqlbot
fonte
Antes de tudo, obrigado pela resposta bem escrita. Eu acho que você propôs uma boa solução. Eu pensei em usar a replicação circular no passado, mas li coisas ruins em relação à sua confiabilidade. No entanto, muitos desses problemas podem ser evitados modificando auto_increment_increment, auto_increment_offset, etc ... Usar o HAProxy localmente nos servidores de aplicativos (apenas como failover) funcionaria bem para nós, pois não precisaríamos modificar nosso aplicativo, abstraindo o failover. lógica longe da camada de aplicação. Vou analisar a configuração do HAProxy, obrigado!
Ethan Hayon
1
Feliz em ajudar. Uma votação positiva seria apreciada se você ainda não o fez. A replicação circular é tão confiável quanto o mestre / escravo (é a mesma tecnologia, apenas nas duas direções), desde que você entenda como funciona e a use de maneira sensata. Desde que os servidores estejam sincronizados corretamente e o aplicativo esteja gravando apenas em um servidor por vez, nunca tive problemas com ele. As auto_increment_*variáveis ​​ainda são boas para usar neste cenário, "por precaução". Além disso, lembre-se de usar binlog_format= rowou mixed- não statement(mesmo que você não esteja fazendo circular).
Michael - sqlbot
Alterei a resposta aceita apenas porque essa explicação detalhada me ajudou a re-arquitetar o sistema para ser mais robusto. A resposta do @ RolandoMySQLDBA ainda está correta e resolve o problema que descrevi inicialmente. Obrigado!
Ethan Hayon
10

Se você estiver usando apenas Master / Slave, aqui está algo rápido e sujo:

SELECT COUNT(1) SlaveThreadCount
FROM information_schema.processlist
WHERE user='system user';

O que isso diz a você?

  • Se SlaveThreadCount= 0, você tem o mestre
  • Se SlaveThreadCount> 0, você tem o Escravo

CAVEAT : Funciona desde que você não executeSTOP SLAVE;

Outra coisa a tentar é o seguinte: se você desabilitar o log binário no escravo e executar SHOW MASTER STATUS;, o Master fornecerá o log binário atual. O Escravo não te dá nada.

RolandoMySQLDBA
fonte
Impressionante, é exatamente isso que eu preciso. Você acha que essa é uma solução confusa para o problema? O único problema que posso imaginar é que os dois servidores estão sendo promovidos para dominar, mas isso nunca deve realmente acontecer.
Ethan Hayon
Se esta resposta é o que você precisava, marque a resposta aceita clicando na marca de seleção na minha resposta.
RolandoMySQLDBA
Eu não pode marcá-lo como aceito por mais 5 minutos :)
Ethan Hayon
Sem problemas. Fiquei feliz por poder ajudar !!!
RolandoMySQLDBA
0

execute esta declaração no prompt do mysql
mysql> show status do escravo;

No escravo, mostra muitos parâmetros e seus valores / status, enquanto no mestre, mostra Conjunto vazio

akrai48
fonte