Alterar captura de dados usando Maxwell para MySQL

O desacoplamento robusto do banco de dados oferece aos desenvolvedores mais liberdade ao ajustar nosso serviço e infraestrutura.

Além disso, também torna nosso tráfego de dados mais eficiente em toda a linha. No entanto, nem sempre vem integrado. Pedimos a um de nossos principais administradores de banco de dados para discutir como alcançamos uma maior dissociação no MySQL:

 

Decidimos fazer algo não convencional procurando uma solução Change Data Capture (CDC) de MySQL para, bem, MySQL.

 

Objetivos

 

O que queríamos alcançar era um desacoplamento melhor entre nossos bancos de dados de origem e de destino. Nós queríamos:

 

Deixe as alterações DDL sem replicação (incluindo instruções perigosas como eliminar banco de dados, eliminar tabela, truncar tabela, eliminar índice, alterar restrição, etc.);

Apenas replique as alterações de dados;

Apenas replique um pequeno subconjunto de tabelas;

Apenas replique um subconjunto de colunas da tabela;

 

Considerações

 

No que diz respeito à questão da consistência, fomos abençoados porque a consistência eventual foi satisfatória para nossos propósitos.

 

A integridade referencial eventual também foi satisfatória, portanto, não havia restrições de chave estrangeira no banco de dados de destino.

 

O suporte para GTID e Galera Cluster foi uma necessidade absoluta para nós. Queremos ter clusters MySQL Galera como servidores de banco de dados de origem e destino.

 

Por que não usamos a replicação do MySQL? A replicação do MySQL funciona muito bem se dois bancos de dados ou esquemas precisam ser mantidos em 100% de sincronia em termos de dados e estrutura. Cada modificação de estrutura (DDL) é imediatamente replicada, que é exatamente o que queríamos evitar.

 

Além disso, a replicação do MySQL e clusters Galera, especialmente quando os bancos de dados de destino são clusters Galera, é uma outra lata de worms.

 

A solução

 

Aqui está uma breve descrição de como funciona a solução CDC:

 

MySQL - Maxwell CDC - Tópico Kafka - Maxwell-coletor gerenciado pelo Kafka Connect - MySQL

 

Maxwell captura alterações do binlog MySQL Galera Cluster e as coloca no tópico Kafka (fila) chamado Maxwell. O Maxwell-sink lê os registros de alteração do tópico Kafka e os aplica ao banco de dados MySQL de destino (Galera Cluster). O coletor Maxwell é gerenciado pelo Kafka Connect.

 

Decidimos usar o Daemon de Maxwell como o mecanismo MySQL Change Data Capture.

 

À parte, o nome “Maxwell's Daemon” tem uma história e tanto por trás dele. O Daemon de Maxwell foi originalmente um experimento mental cativante que ainda está provocando discussões mais de cem anos após sua introdução.

 

O que o Maxwell's Daemon faz é consumir logs binários do MySQL e produzir mensagens JSON em seu próprio formato. As mensagens são razoavelmente bem documentadas e simples.

 

O Daemon de Maxwell também possui um procedimento inicial de carregamento de dados chamado bootstrapping. A inicialização pode ser iniciada e interrompida a qualquer momento. O único problema com o bootstrap do Maxwell é que as mudanças (pelo menos as que estão sendo feitas na tabela bootstrapped) são interrompidas enquanto a tabela está sendo bootstrapped. Mas assim que o bootstrap termina, o fluxo de mudanças continua. Recomendo fortemente a leitura da descrição de Maxwell sobre como configurar e executar o bootstrap.

 

O Maxwell's Daemon integra-se a vários servidores de enfileiramento para transferir as mensagens de mudança capturadas. Escolhemos Kafka.

 

Por enquanto, tudo bem. No entanto, uma parte ainda está faltando aqui. Precisamos de algum tipo de software para ler as mensagens de mudança e aplicá-las ao banco de dados MySQL de destino. ( O motivo pelo qual Maxwell tem seu próprio formato de mensagem é que o Kafka Connect veio depois do Daemon de Maxwell. Veja esta discussão para obter mais informações . )

 

Nossa solução foi fazer um fork desse coletor Kafka Connect específico , que é capaz de analisar as mensagens de Maxwell e aplicá-las ao destino do MySQL.

 

O que fizemos com o garfo Maxwell-pia

 

Fizemos algumas mudanças importantes no garfo Maxwell-sink:

 

Lógica de atualização / inserção / exclusão alterada (veja abaixo para mais detalhes);

Suporte para atualizações de coluna de chave primária;

Suporte para filtragem de coluna;

Log de diagnóstico modificado, incluindo mensagens de diagnóstico mais informativas sobre erros;

Suporte para mensagens de bootstrap do Maxwell;

O último GTID aplicado é registrado para fins de diagnóstico;

Lance exceções e pare em quaisquer erros de “aplicação” (não queremos perder uma única mensagem de Maxwell);

Alterada a lógica para dados sobrepostos. Se já existir um registro, ele será sobrescrito.

Nosso critério de design era lidar com dados sobrepostos. Não queríamos que o fluxo do CDC parasse se:

 

já existe um registro a ser inserido (neste caso apenas atualizamos);

um registro a ser excluído já foi excluído ou nunca existiu em primeiro lugar;

ou não existe um registro a ser atualizado (neste caso, nós o criamos).

Isso cobre praticamente todos os casos de sobreposição de dados.

 

O leitor perspicaz notará que lidar com dados dessa maneira pode levar a problemas de integridade referencial e, conseqüentemente, de chaves estrangeiras. No entanto, como dissemos no início, não temos chaves estrangeiras no banco de dados de destino. Garantimos que cada registro filho eventualmente chegue ao banco de dados de destino. A mesma regra se aplica a todo registro pai. Nosso objetivo é alcançar a consistência eventual, ou seja, garantir que os dados mais recentes cheguem eventualmente.

 

Considerações de alta disponibilidade

 

Maxwell's Daemon é um motor de CDC bem pensado.

 

A tentativa de iniciar mais de uma instância do Daemon produzirá um erro. A julgar pela mensagem de erro, Maxwell usa algum tipo de método de bloqueio. Ele reclama sobre uma sequência de etapas fora de ordem e sai.

 

Esta propriedade é extremamente importante. É fácil imaginar que dois streams de Maxwell paralelos podem criar problemas de dados na extremidade receptora. Se esses dois (ou mais) fluxos rodarem em paralelo indefinidamente, então as coisas podem acabar bem, além do impacto no desempenho. Mas se um stream terminar em algum ponto, você pode muito bem perder uma exclusão. As exclusões, como operações a serem replicadas, estão em sua própria classe e devem ser tratadas com cuidado.

 

Na extremidade do coletor, contamos com a capacidade do Kafka-Connect de garantir que apenas um coletor esteja funcionando por vez.

 

Por fim, precisamos ter certeza de que temos pelo menos 2 instâncias de cada componente: Maxwell's Daemon, um cluster Kafka de vários nós com todos os tópicos Kafka replicados corretamente, o coletor de Maxwell e, por último, mas não menos importante, MySQL de vários nós Clusters Galera para bancos de dados de origem e destino.

 

Ao testar o Kafka Connect, descobrimos um pequeno problema com a configuração do Kafka Connect. O valor padrão deconsumer.max.poll.interval.msera muito grande. Como resultado, levou algum tempo para o coletor se reequilibrar para um nó íntegro depois que qualquer um dos nós Kafka travou. Configurá-lo para 30 segundos (use o valor 30000) ajudou.

 

Epílogo

 

Esta solução está em execução no ambiente de desenvolvimento há mais de meio ano sem problemas.

 

No entanto, sempre há (pelo menos) uma última coisa a se considerar. Um desses problemas é a reversão.

 

O Daemon de Maxwell produz informações transacionais em suas mensagens, incluindo um xid (um id de transação) e commit: trueCampos.

 

Felizmente, nosso fluxo de log binário do banco de dados de origem nunca produziu registros que foram revertidos. Nosso código de aplicativo usa transações e potencialmente até mesmo uma reversão, mas parece que as transações são revertidas antes mesmo de serem inseridas nos logs binários. De acordo com este documento , o MySQL não deve gravar registros no log binário que não foram confirmados ou que foram potencialmente revertidos, mas há um documento interessante do Debezium sobre o assunto.

 

Nesse documento, diz:

 

“Sob condições específicas, é possível que o binlog do MySQL contenha dados não confirmados concluídos por uma instrução ROLLBACK. Exemplos típicos são o uso de pontos de salvamento ou a combinação de alterações temporárias e regulares de tabela em uma única transação. ”

 

Independentemente disso, regularmente executamos comparações simples de tabelas de origem e destino para garantir que os dados correspondam até um ponto fixo recente no tempo. Até agora, está tudo bem.

 

Demos uma boa corrida à solução, examinamos e aprendemos com ela. Por fim, desenvolvemos outra solução baseada na primeira. Ele tem suas próprias desvantagens, mas também tem algumas propriedades muito boas que estavam faltando na primeira versão. Você sabe o que eles dizem - coisas boas vêm para aqueles que repetem. Mas isso é uma história para outra postagem do blog de Engenharia no Avance Network.

 

 

O Avance Network é uma comunidade fácil de usar que fornece segurança de primeira e não requer muito conhecimento técnico. Com uma conta, você pode proteger sua comunicação e seus dispositivos. O Avance Network não mantém registros de seus dados; portanto, você pode ter certeza de que tudo o que sai do seu dispositivo chega ao outro lado sem inspeção.


Strong

5178 بلاگ پوسٹس

تبصرے