Estamos usando MySQL DB com um mestre e um escravo. Estamos usando essa configuração há meses. A sincronização do escravo parou hoje e o erro que recebemos foi:
Last_IO_Errno: 1236
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master'
Last_SQL_Errno: 1594
Last_SQL_Error: Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog' on the binary log), the slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log), a network problem, or a bug in the master's or slave's MySQL code. If you want to check the master's binary log or slave's relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' on this slave.
Tentamos reiniciar o serviço mysql do escravo e iniciar e parar a replicação do escravo sem ajuda. Após uma investigação mais aprofundada, descobrimos que havia um problema com o tamanho particularmente grande da consulta. No log de erros do servidor mestre, obtivemos o log de erros como abaixo:
[ERROR] Error in Log_event::read_log_event(): 'Event too big', data_len: 1936941420, event_type: 109
Identificamos a consulta que causou esse problema. Podemos ignorar a atualização dessa consulta. Este erro é registrado constantemente no log de erros do mysql.
O problema é que o mestre não é capaz de ler o registro do relé após essa posição específica do registro. Queremos apenas remover esse número de log de retransmissão específico do log binário do servidor mestre. Como podemos remover uma determinada entrada de log de retransmissão do arquivo de log binário? E sim, temos uma situação crítica com o aplicativo devido a isso. :(
Uma possível solução que vem à mente é definir o master_log_position para o próximo:
Ou apenas use sql_slave_skip_counter = 1 . Se isso não funcionar, você pode tentar analisar o binlog (se o mysqlbinlog puder analisá-lo ...):
Edite o script e remova a parte até e incluindo a declaração longa. Execute o script modificado manualmente no escravo e defina o master_logfile para o próximo binlog:
Você também pode verificar, por precaução, se o mestre e o escravo usam o mesmo *max_allowed_packet*.
Há algum tempo, tínhamos um log binário corrompido no mestre devido a alguns problemas graves com o SAN, que fazia coisas que um SAN realmente não deveria fazer, como escrever blocos de zeros em vez dos dados reais, que aprendemos depois.
Minha solução foi pular os blocos quebrados/entradas de log definindo master_log_position nos escravos para a próxima instrução válida no log de bin mestre e esperar que as instruções ignoradas/ausentes não quebrassem nada no nível lógico, também conhecido como escravo reclamando de duplicata chave e essas coisas depois.
O problema é encontrar a próxima posição válida dentro do log binário neste caso.
Então, dei uma olhada na documentação do desenvolvedor do mysql para conhecer a estrutura interna do log binário e examinei meu log binário mestre quebrado com um editor hexadecimal. A posição da última entrada válida pode ser vista no escravo, comece a partir daí.
Como o log binário continha as instruções sql gravadas quase na forma de texto, pude identificar a posição das próximas instruções INSERT / UPDATE / algo. Subtraia o tamanho dos campos de cabeçalho do log binário antes da instrução real (consulte a documentação do desenvolvedor), defina master_log_position para esse valor e reinicie o escravo. Se você acertar uma posição válida ele vai continuar, senão ele vai reclamar. Você pode usar mysqlbinlog para despejar a instrução nessa posição também.
Isso não é nada para os fracos de coração e não posso fornecer instruções passo a passo mais detalhadas.
Se o seu log binário está realmente corrompido (e para mim parece assim, date_len é puxado de um campo no log bin e este não é um valor válido, é por isso que o escravo está reclamando) a solução do livro é reconstruir o escravo restaurando um novo backup do mestre para o escravo (etc., como configurar um novo escravo), pois você não pode dizer depois se os dados estão realmente sincronizados com seu mestre porque você pulou algumas instruções.
Esse erro geralmente é causado por uma falha de hardware ou um bug tão vago que não é encontrado há mais de uma década. A solução ideal que irá corrigi-lo definitivamente sem qualquer risco de anomalias é reinicializar totalmente a replicação. Você pode fazer isso sem tempo de inatividade ou bloqueio usando
xtrabackup
oumysqldump --single-transaction
.Primeiro de tudo você precisa ver a
SHOW SLAVE STATUS\G
saída. Lá você pode encontrar seu mysqlbinlog.A replicação pode ser cara se você tiver terabytes de dados, portanto, pode haver uma maneira de restaurar a replicação sem reconstruir o escravo completamente. Você pode usar mysqlbinlog no mestre para identificar onde a transação é iniciada e procurar a posição próxima (seu
Exec_Master_Log_Pos
). Há uma chance muito boa de que a posição listada realmente tenha um erro e nenhuma transação no log binário comece nessa posição. Também é muito provável que você descubra que as distâncias coordenadas entre essas transações não estão nem perto do seumax_allowed_packet
valor.Se for esse o caso, você pode redefinir suas coordenadas de replicação no escravo para as últimas listas mysqlbinlog de transação que estão antes da posição em que o escravo pensa que está. Você pode encontrar mais detalhes sobre exatamente o que fazer neste artigo de solução de problemas do MariaDB e do MySQL .
Na maioria dos casos, se houver uma chave primária e estivermos usando
binlog_format=ROW
, a replicação será interrompida em uma linha ausente (em uma exclusão) ou em uma chave duplicada (em um INSERT), e podemos pular a transação e continuar.Sim, definir master_log_position para a próxima instrução válida é o caminho a seguir.
Uma boa maneira de encontrar a posição correta do log é usar a opção --hexdump no mysqlbinlog, assim:
Você pode ver que a instrução foi corrompida no meio do bloco e o próximo registro está começando em 0x6202000 (31830156 é o próximo registro de data e hora no formato little endian). 0x6202000 é 102768640 decimal.
Então a correção é: