MariaDB
 sql >> Base de Dados >  >> RDS >> MariaDB

Lidando com problemas de replicação de clusters de banco de dados não-GTID para GTID MariaDB

Recentemente, encontramos um caso interessante de suporte ao cliente envolvendo uma configuração de replicação do MariaDB. Passamos muito tempo pesquisando esse problema e achamos que valeria a pena compartilhar isso com você nesta postagem do blog.

Descrição do ambiente do cliente

O problema era o seguinte:um servidor MariaDB antigo (pré 10.x) estava em uso e foi feita uma tentativa de migrar dados dele para uma configuração de replicação MariaDB mais recente. Isso resultou em problemas com o uso do Mariabackup para reconstruir escravos no novo cluster de replicação. Para fins de testes, recriamos esse comportamento no seguinte ambiente:

Os dados foram migrados de 5.5 para 10.4 usando mysqldump:

mysqldump --single-transaction --master-data=2 --events --routines sbtest > /root/dump.sql

Isso nos permitiu coletar as coordenadas do log binário mestre e o dump consistente. Como resultado, conseguimos provisionar o nó mestre do MariaDB 10.4 e configurar a replicação entre o antigo mestre 5.5 e o novo nó 10.4. O tráfego ainda estava em execução no nó 5.5. O mestre 10.4 estava gerando GTIDs, pois tinha que replicar dados para o escravo 10.4. Antes de nos aprofundarmos nos detalhes, vamos dar uma olhada rápida em como os GTIDs funcionam no MariaDB.

MariaDB e GTID

Para começar, o MariaDB usa um formato de GTID diferente do Oracle MySQL. É composto por três números separados por traços:

0 - 1 - 345

Primeiro é um domínio de replicação, que permite que a replicação de várias fontes seja tratada adequadamente. Isso não é relevante para o nosso caso, pois todos os nós estão no mesmo domínio de replicação. O segundo número é o ID do servidor do nó que gerou o GTID. O terceiro é o número de sequência - ele aumenta monotonicamente com cada evento armazenado nos logs binários.

MariaDB usa diversas variáveis ​​para armazenar as informações sobre os GTIDs executados em um determinado nó. Os mais interessantes para nós são:

Gtid_binlog_pos - conforme a documentação, esta variável é o GTID do último grupo de eventos gravado no log binário.

Gtid_slave_pos - conforme a documentação, esta variável de sistema contém o GTID da última transação aplicada ao banco de dados pelas threads escravas do servidor.

Gtid_current_pos - conforme a documentação, esta variável de sistema contém o GTID da última transação aplicada ao banco de dados. Se o server_id do GTID correspondente em gtid_binlog_pos for igual ao server_id do próprio servidor e o número de sequência for maior que o GTID correspondente em gtid_slave_pos, então o GTID de gtid_binlog_pos será usado. Caso contrário, o GTID de gtid_slave_pos será usado para esse domínio.

Então, para deixar claro, gtid_binlog_pos armazena o GTID do último evento executado localmente. Gtid_slave_pos armazena o GTID do evento executado pela thread escrava e gtid_current_pos mostra o valor de gtid_binlog_pos, se tiver o número de sequência mais alto e tiver server-id ou gtid_slave_pos se tiver a sequência mais alta. Por favor, mantenha isso em sua mente.

Uma visão geral do problema

O estado inicial das variáveis ​​relevantes está no 10.4 master:

MariaDB [(none)]> show global variables like '%gtid%';

+-------------------------+----------+

| Variable_name           | Value |

+-------------------------+----------+

| gtid_binlog_pos         | 0-1001-1 |

| gtid_binlog_state       | 0-1001-1 |

| gtid_cleanup_batch_size | 64       |

| gtid_current_pos        | 0-1001-1 |

| gtid_domain_id          | 0 |

| gtid_ignore_duplicates  | ON |

| gtid_pos_auto_engines   | |

| gtid_slave_pos          | 0-1001-1 |

| gtid_strict_mode        | ON |

| wsrep_gtid_domain_id    | 0 |

| wsrep_gtid_mode         | OFF |

+-------------------------+----------+

11 rows in set (0.001 sec)

Observe gtid_slave_pos que, teoricamente, não faz sentido - veio do mesmo nó, mas via encadeamento escravo. Isso pode acontecer se você fizer um switch mestre antes. Fizemos exatamente isso - com dois nós 10.4, trocamos os mestres de host com ID de servidor de 1001 para host com ID de servidor de 1002 e depois voltamos para 1001.

Depois configuramos a replicação de 5.5 para 10.4 e ficou assim:

MariaDB [(none)]> show global variables like '%gtid%';

+-------------------------+-------------------------+

| Variable_name           | Value |

+-------------------------+-------------------------+

| gtid_binlog_pos         | 0-55-117029 |

| gtid_binlog_state       | 0-1001-1537,0-55-117029 |

| gtid_cleanup_batch_size | 64                      |

| gtid_current_pos        | 0-1001-1 |

| gtid_domain_id          | 0 |

| gtid_ignore_duplicates  | ON |

| gtid_pos_auto_engines   | |

| gtid_slave_pos          | 0-1001-1 |

| gtid_strict_mode        | ON |

| wsrep_gtid_domain_id    | 0 |

| wsrep_gtid_mode         | OFF |

+-------------------------+-------------------------+

11 rows in set (0.000 sec)

Como você pode ver, os eventos replicados do MariaDB 5.5, todos eles foram contabilizados na variável gtid_binlog_pos:todos os eventos com ID de servidor 55. Isso resulta em um problema sério. Como você deve se lembrar, gtid_binlog_pos deve conter eventos executados localmente no host. Aqui ele contém eventos replicados de outro servidor com ID de servidor diferente.

Isso torna as coisas arriscadas quando você quer reconstruir o escravo 10.4, eis o porquê. O Mariabackup, assim como o Xtrabackup, funciona de forma simples. Ele copia os arquivos do servidor MariaDB enquanto verifica os redo logs e armazena todas as transações recebidas. Quando os arquivos forem copiados, o Mariabackup congelará o banco de dados usando FLUSH TABLES WITH READ LOCK ou bloqueios de backup, dependendo da versão do MariaDB e da disponibilidade dos bloqueios de backup. Em seguida, ele lê o último GTID executado e o armazena junto com o backup. Em seguida, o bloqueio é liberado e o backup é concluído. O GTID armazenado no backup deve ser usado como o último GTID executado em um nó. No caso de reconstrução de escravos, ele será colocado como gtid_slave_pos e então usado para iniciar a replicação do GTID. Este GTID é retirado de gtid_current_pos, o que faz todo o sentido - afinal é o “GTID da última transação aplicada ao banco de dados”. O leitor aguçado já pode ver o problema. Vamos mostrar a saída das variáveis ​​quando 10.4 replica do mestre 5.5:

MariaDB [(none)]> show global variables like '%gtid%';

+-------------------------+-------------------------+

| Variable_name           | Value |

+-------------------------+-------------------------+

| gtid_binlog_pos         | 0-55-117029 |

| gtid_binlog_state       | 0-1001-1537,0-55-117029 |

| gtid_cleanup_batch_size | 64                      |

| gtid_current_pos        | 0-1001-1 |

| gtid_domain_id          | 0 |

| gtid_ignore_duplicates  | ON |

| gtid_pos_auto_engines   | |

| gtid_slave_pos          | 0-1001-1 |

| gtid_strict_mode        | ON |

| wsrep_gtid_domain_id    | 0 |

| wsrep_gtid_mode         | OFF |

+-------------------------+-------------------------+

11 rows in set (0.000 sec)

Gtid_current_pos está definido como 0-1001-1. Este definitivamente não é o momento correto, foi tirado de gtid_slave_pos enquanto temos um monte de transações que vieram de 5.5 depois disso. O problema é que essas transações são armazenadas como gtid_binlog_pos. Por outro lado, gtid_current_pos é calculado de uma forma que requer o ID do servidor local para GTIDs em gitd_binlog_pos antes que eles possam ser usados ​​como gtid_current_pos. No nosso caso, eles têm o ID do servidor do nó 5.5, portanto, não serão tratados adequadamente como eventos executados no mestre 10.4. Após a restauração do backup, se você configurasse o escravo de acordo com o estado do GTID armazenado no backup, ele acabaria reaplicando todos os eventos que vieram do 5.5. Isso, obviamente, quebraria a replicação.

A solução

Uma solução para esse problema é executar várias etapas adicionais:

  1. Parar a replicação de 5.5 para 10.4. Execute STOP SLAVE no mestre 10.4
  2. Execute qualquer transação em 10.4 - CREATE SCHEMA IF NOT EXISTS bugfix - isso mudará a situação do GTID assim:
MariaDB [(none)]> show global variables like '%gtid%';

+-------------------------+---------------------------+

| Variable_name           | Value   |

+-------------------------+---------------------------+

| gtid_binlog_pos         | 0-1001-117122   |

| gtid_binlog_state       | 0-55-117121,0-1001-117122 |

| gtid_cleanup_batch_size | 64                        |

| gtid_current_pos        | 0-1001-117122   |

| gtid_domain_id          | 0   |

| gtid_ignore_duplicates  | ON   |

| gtid_pos_auto_engines   |   |

| gtid_slave_pos          | 0-1001-1   |

| gtid_strict_mode        | ON   |

| wsrep_gtid_domain_id    | 0   |

| wsrep_gtid_mode         | OFF   |

+-------------------------+---------------------------+

11 rows in set (0.001 sec)

O GITD mais recente foi executado localmente, então foi armazenado como gtid_binlog_pos. Como tem o ID do servidor local, é escolhido como gtid_current_pos. Agora, você pode fazer um backup e usá-lo para reconstruir escravos do mestre 10.4. Feito isso, inicie o thread escravo novamente.

MariaDB está ciente de que esse tipo de bug existe, um dos relatórios de bug relevantes que encontramos é: https://jira.mariadb.org/browse/MDEV-10279 Infelizmente, não há correção até agora . O que descobrimos é que esse problema afeta o MariaDB até 5.5. Eventos não-GTID que vêm do MariaDB 10.0 são contabilizados corretamente em 10.4 como provenientes do encadeamento escravo e gtid_slave_pos é atualizado corretamente. O MariaDB 5.5 é bastante antigo (embora ainda seja suportado), então você ainda pode ver configurações em execução nele e tentar migrar de 5.5 para versões mais recentes do MariaDB habilitadas para GTID. O que é pior, de acordo com o relatório de bug que encontramos, isso também afeta a replicação vinda de servidores não-MariaDB (um dos comentários menciona o problema que aparece no Percona Server 5.6) em servidores MariaDB.

De qualquer forma, esperamos que você tenha achado esta postagem do blog útil e esperamos que você não se depare com o problema que acabamos de descrever.