Existe uma maneira melhor de sair do log do MySQL InnoDB "no futuro"?

16

Eu tenho esse erro do InnoDB no MySQL 5.0. O Mysqld foi parado de maneira limpa, mas eu consegui perder o ib_logfile0 e o ib_logfile1 posteriormente. Agora, após uma inicialização limpa, o InnoDB fez sua "recuperação de falha". Passei pela empresa innodb_force_recovery = 4, consertei uma tabela MyISAM suspensa e agora a replicação está pronta, além disso. Grandes números confirmados:

111116 15:49:36  InnoDB: Error: page 393457 log sequence number 111 561,760,232
InnoDB: is in the future! Current system log sequence number 70 3,946,969,851.
InnoDB: Your database may be corrupt or you may have copied the InnoDB
InnoDB: tablespace but not the InnoDB log files. See
InnoDB: http://dev.mysql.com/doc/refman/5.0/en/forcing-recovery.html
InnoDB: for more information.

Este está em um servidor escravo. O erro acima vomita às centenas. Eu encontrei esta resposta: "insira e exclua mais de 64 GB de dados, para que o número de sequência do log fique inflado suficientemente grande".

http://forums.mysql.com/read.php?22,50163,50163#msg-50163

Esse número mágico de 64 GB vem de 4 GB * 16, em que o "número principal" do registro do innodb desse cara precisava aumentar de 0 para 15. O meu passou de 70 para 111 = 164 GB. Isso levará 5 dias. Continuarei trabalhando para acelerar meu script e executá-lo em paralelo para acelerar isso. Enquanto isso, espero que outra pessoa tenha uma resposta melhor. Isso é bobo.

IcarusNM
fonte
Uma resposta promissora: "Se for um servidor escravo, a melhor solução seria realmente afastar o banco de dados e instalar um novo instantâneo do mestre". Infelizmente, existem 20.000 tabelas em 25 bancos de dados, uma mistura de MyISAM e InnoDB, na produção 24x7. Levaria muito tempo para desligar tudo isso e fazer uma replicação completa completa antes de iniciar a replicação novamente.
IcarusNM 17/11
4
Agora tenho essa máquina de 8 núcleos de joelhos em uma corrida sem sentido para criar e excluir 164 GB de dados. A única alternativa que estou ouvindo é destruir tudo sobre esse escravo e começar do zero. Tudo para alterar efetivamente um número em dois arquivos. Certamente há algum engenheiro do InnoDB por aí com uma dica profissional. Alguém já abriu o ib_logfile0 no Emacs, encontrou o número mágico em hexadecimal e apenas o mudou?
IcarusNM 17/11
Aqui está um ótimo artigo sobre algumas maneiras de fazer isso. Percona é definitivamente a autoridade no MySQL. percona.com/blog/2013/09/11/...
jbrahy

Respostas:

10

Essa era uma situação bastante rara. Espero nunca mais chegar lá novamente, com um InnoDB "número de sequência de log está no futuro!" erro. Por causa dos meus detalhes particulares, a reconstrução / restauração dos dados do meu servidor foi o último recurso. Alguns truques para ajudar foram boas idéias, mas no final, decidi continuar melhorando meu script Perl para jogar esse jogo bobo e agitar o máximo de shows / hora que pude. Que diabos, é um bom teste de estresse do sistema.

Lembre-se: o objetivo é aumentar um único contador ("número de sequência do log") que é armazenado em algum lugar nos cabeçalhos de ib_logfile0 e ib_logfile1 . Isso é para falsificar o InnoDB, para que ele ignore um aparente tempo distorcido e continue com a vida. Mas ninguém sabe como editar esse número. Ou se eles sabem, ninguém está falando.

Aqui está o meu produto final. YMMV, mas usar a função REPEAT do mysql para gerar os dados internamente é altamente eficiente.

 #!/usr/bin/perl
 use DBI;
 $table = shift || die;
 $dbh = DBI->connect("DBI:mysql:junk:host=localhost", "user", "pass"); #Edit "junk" (DB name), user, and pass to suit.
 $dbh->do("DROP TABLE IF EXISTS $table");
 $dbh->do("CREATE TABLE $table (str TEXT) ENGINE=INNODB");
 $sth = $dbh->prepare("INSERT INTO $table (str) VALUES (REPEAT(?,1000000))");
 foreach (1..50) {
    $sth->execute('0123456789');   # 10 MB
 }
 $dbh->do("DELETE FROM $table");

Minha receita sugerida:

  1. Crie um banco de dados 'lixo'
  2. Salve o script perl acima como junk.pl .
  3. Execute junk.pl data1 e junk.pl data2 e junk.pl data3 , etc. todos de uma vez, para iniciar o número de núcleos de CPU que o servidor de banco de dados possui. Abra várias conchas e enrole cada corrida em um circuito Bash: while true; do date; junk.pl dataX; done.

Assista seu LSN crescer, talvez em outro loop:

 silly# echo "SHOW INNODB STATUS \G" | mysql -p'xxxxxx' | grep '^Log seq'
 Log sequence number 124 3871092821
 silly# echo "SHOW INNODB STATUS \G" | mysql -p'xxxxxx' | grep '^Log seq'
 Log sequence number 124 4209892586
 silly# echo "SHOW INNODB STATUS \G" | mysql -p'xxxxxx' | grep '^Log seq'
 Log sequence number 125 85212387

O grande número é um INT de 32 bits não assinado, com quebra de 4 GB, aumentando sempre o número menor. Neste caso acima, ele passou de 124 para 125. Seu objetivo está oculto no mysqld.log que o enviou pesquisando no Google essa solução ridícula em primeiro lugar. Depois de cruzar a linha de chegada, é isso! Sopre os chifres! Solte o confete!

Barra Lateral: Isso descobriu um bug interessante no mysqld 5.0 com REPEAT: se você vai para 20 MB, ele vira algum contador interno e rola para ~ 96 KB. Nenhum aviso ou erro em qualquer lugar. Eu não estava prestes a perder tempo rastreando isso. 10 MB funciona muito bem. Se você atingir outro limite, pode reclamar. Eu tenho vários buffers innodb aumentados do padrão. Tempere a gosto. Como sempre, assista o mysqld.log em uma janela.

IcarusNM
fonte
Verifique isso percona.com/blog/2013/09/11/…
Jonas Stensved
Obrigado Jonas; isso é interessante. Eu acho que posso ficar com o meu método acima. Ele mostra o uso do gdb no mysqld em execução, o qual eu provavelmente nunca arriscaria. Mas boa informação lá também.
IcarusNM
Por alguma estranha razão, usando o MariaDB, não recebo os números de sequência de log 'pequeno número [espaço] grande número' - mas apenas um 'grande número', então, infelizmente, esse método não funcionou para mim. Bem, é claro, o log é atualizado, eu simplesmente não sei quando parar!
Gwyneth Llewelyn
5

Você tem três (3) opções:

OPÇÃO 01: Executar rsync do mestre para o escravo (tempo de inatividade no mestre)

  • Etapa 01: executar reset master;no mestre (registros binários do Zaps)
  • Etapa 02: service mysql stopno mestre
  • Etapa 03: service mysql stopno escravo
  • Etapa 04: rsync / var / lib / mysql do mestre para o escravo
  • Etapa 05: service mysql startno mestre
  • Etapa 06: Use o primeiro log binário no mestre como o log para iniciar a replicação. Use o tamanho do arquivo desse log como a posição para iniciar a replicação a partir de
  • Etapa 07: service mysql stop --skip-slave-startno escravo
  • Etapa 08: Execute o comando CHANGE MASTER TO para configurar a replicação a partir do log e a posição determinada na Etapa 06
  • Etapa 09: execute start slave;o escravo e deixe a replicação recuperar o atraso

OPÇÃO 02: Executar rsync do mestre para o escravo (tempo de inatividade mínimo no mestre)

  • Etapa 01: executar reset master;no mestre (registros binários do Zaps)
  • Etapa 02: service mysql stopno escravo
  • Etapa 03: rsync / var / lib / mysql do mestre para o escravo
  • Etapa 04: Repita a Etapa 03 até que dois rsyncs consecutivos levem a mesma quantidade de tempo
  • Etapa 05: service mysql stopno mestre
  • Etapa 06: rsync / var / lib / mysql do mestre para o escravo
  • Etapa 07: service mysql startno mestre
  • Etapa 08: Use o primeiro log binário no mestre como o log para iniciar a replicação. Use o tamanho do arquivo desse log como a posição para iniciar a replicação a partir de
  • Etapa 09: service mysql stop --skip-slave-startno escravo
  • Etapa 10: Execute o comando CHANGE MASTER TO para configurar a replicação a partir do log e a posição determinada na Etapa 08
  • Etapa 11: execute start slave;o escravo e deixe a replicação recuperar o atraso

OPÇÃO 03: Use o XtraBackup

Essa ferramenta de software não apenas fará uma cópia não invasiva de um mestre em execução, mas também criará os ib_logfiles correspondentes para você. Você precisaria configurar a replicação

Eu já postei no StackExchange antes sobre esse assunto

Eu já fiz isso várias vezes pela empresa de hospedagem na web do meu empregador. Um cliente tinha 3,7 TB para mover e levou cerca de 16 horas. 64GB é muito pequeno em comparação.

RolandoMySQLDBA
fonte
Na OPÇÃO 02 Etapa 05, você diz para iniciar o mestre. Quando foi parado? Rsync em um mestre ao vivo é corajoso. Estou impressionado. E, felizmente, estou usando innodb_file_per_table. Mas, eventualmente, você precisa morder o marcador e parar o mestre por tempo suficiente para que um rsync final seja executado antes de iniciar a replicação. É possível que eu possa recorrer, mas esse é um DBMS muito ativo. E vou procurar no XtraBackup minhas informações.
IcarusNM 17/11
@IcarusNM: Ah, erro de digitação. Eu corrigi isso. Obrigado !!!
RolandoMySQLDBA
A OPÇÃO 02 provavelmente ainda poderia usar algum trabalho. Por exemplo, você deve executar o passo 2 antes do passo 1. Você provavelmente quer um RESET SLAVE em algum lugar. Erro de digitação na etapa 4. E você diz "primeiro log binário" na etapa 5, mas realmente quer dizer "somente" ou "último" log binário. E você deve usar o mysqlbinlog para verificar as posições do log, não o tamanho do arquivo. E tudo isso ainda não funcionará, a menos que você pare o mestre em algum momento. Basear uma posição / hora do log em quando um rsync termina é, na melhor das hipóteses, arriscado.
IcarusNM
Venho fazendo a OPÇÃO 2 nos últimos 4 anos com clientes de DB Hosting que possuem dados na faixa TeraByte. Funciona sempre contra um servidor em execução. O único erro real que você pode cometer é o escravo. Esse erro seria se a replicação foi configurada corretamente ou não. Além disso, RESET SLAVEé útil, especialmente se você tiver acumulado muitos GB de logs de retransmissão. Após o processo rsync e o restabelecimento da replicação, lembre-se de que o comando CHANGE MASTER TO também apagará os logs de retransmissão para você.
RolandoMySQLDBA
mmm ... estranho. Eu configurei meu escravo usando xtrabackup (como sempre) e ainda tenho esses erros de log (percona mysql 5.5.x) ... parece que houve algo errado com esse escravo e tenho que fazê-lo novamente.
Harald
2

Descobri que talvez haja uma maneira mais legal de resolver esse problema trabalhando em tabelas particionadas. Eu precisava descartar partições de alguns anos atrás e tive que adicionar algumas para 2014. Quase todas as partições relatam esse erro, também as antigas. Acidente muito desagradável.

Portanto, enquanto DROPPING antiga e usando REORGANIZE da partição MAXVALUE (a última), ela criará novos arquivos que estão bem, então recebo cada vez menos avisos. Enquanto isso, ajuda a incrementar o contador de sequência de log, portanto, não preciso inserir dados falsos. Eu tenho isso acontecendo em um servidor mestre btw ...

Então, é isso:

ALTER TABLE Events DROP PARTITION p1530 , p1535 , p1540 , p1545 , 
p1550, p1555 , p1560 , p1565 , p1570 , p1575 , p1580 , p1585 , p1590 , 
p1595 , p1600 , p1605 , p1610 , p1615 , p1620 , p1625 , p1630 , p1635 , 
p1640 , p1645 , p1650 , p1655 , p1660 , p1665 , p1670 , p1675 , p1680 , 
p1685 , p1690 , p1695 , p1700 , p1705 , p1710 , p1715 , p1720 , p1725 , 
p1730 , p1735 , p1740 , p1745 , p1750 , p1755 , p1760 , p1765 , p1770 , 
p1775 , p1780 , p1785 , p1790 , p1795 , p1800 , p1805 , p1810 , p1815 , 
p1820 , p1825 , p1830 , p1835 , p1840;

E isto:

ALTER table Events REORGANIZE PARTITION p3000 INTO (
PARTITION p3500 VALUES LESS THAN (TO_DAYS('2013-01-01')),
PARTITION p3510 VALUES LESS THAN (TO_DAYS('2013-01-04')),
PARTITION p3520 VALUES LESS THAN (TO_DAYS('2013-01-07')),
PARTITION p3530 VALUES LESS THAN (TO_DAYS('2013-01-10'))
...
PARTITION p4740 VALUES LESS THAN (TO_DAYS('2014-01-08')),
PARTITION p9000 VALUES LESS THAN MAXVALUE)

Isso eliminará efetivamente cada partição da mudança e a recriará com uma cópia temporária do conteúdo do que estava lá. Você pode fazer isso por tabela, se quiser, meu aplicativo permite que isso aconteça, portanto, não há necessidade de se preocupar com backups sincronizados, etc.

Agora, para o restante da tabela, como não toquei em todas as partições no processo, algumas serão deixadas com o aviso de sequência de log; para aquelas que estão quebradas, mas cobertas por essa ação de reorganização, provavelmente executarei o seguinte:

ALTER TABLE Events REBUILD PARTITION p0, p1;

ou aquilo

ALTER TABLE Events OPTIMIZE PARTITION p0, p1;

Então, isso me fez pensar: você poderia fazer isso com tabelas simples, adicionar partições temporariamente por hash e depois removê-lo (ou mantê-las, eu recomendo fortemente partições).

No entanto, estou usando o mariadb, não o mysql (portanto, o XtraDB)

Talvez isso ajude alguém. Eu ainda estou executando, até agora tudo bem. Mudar o MOTOR parece fazer o trabalho também, então eu o troco entre o MyIsam e eles de volta ao InnoDB.

É bastante lógico, se você mudar ENGINE, a tabela desaparecerá do innodb, portanto não será mais um problema.

ALTER TABLE Events ENGINE=MyISAM;
ALTER TABLE Events ENGINE=InnoDB;

parece funcionar aqui. Posso confirmar algumas coisas nas tabelas particionadas:

  • ALTER TABLE xyz ENGINE = O InnoDB é muito lento, para Aria (mariadb) duas vezes mais rápido, mas em geral uma maneira lenta de incrementar o contador de sequência de log
  • ALTER TABLE xyz REBUILD PARTITION ALL é a maneira mais rápida de 'consertar' as tabelas e ajudar a incrementar o contador
  • ALTER TABLE xyz ANALYZE PARTITION ALL é lento em comparação com o anterior e não reescreve as partições que parecem estar ok. REBUILD garante uma reescrita para um esquema de tabela temporária.

Eu usei os últimos em várias mesas. Os avisos acontecem quando ele tenta abrir os arquivos e há um para cada definição de partição que é aberta com problemas de contador. Hoje quase rolou no balcão hoje para as últimas mesas. Acho que uma vez processado, é necessário liberar os logs binários.

atualização : posso concluir algumas coisas agora que consegui resolver esse problema.

  • Minha falha foi causada pela reorganização de partições em uma tabela no formato Aria (MariaDB).
  • (para mim) fazer uma reconstrução das partições funcionou melhor e mais rápido para obter o contador de sequências. Alterar o mecanismo é lento e você precisa fazer isso duas vezes para afetar o innodb. alterar para o innoDB é bastante lento vs. para MyIsam ou Aria.
  • Atualizei para o MariaDB 5.3 e não para 5.5 (era: 5.2) e funciona bem. Eu acho que há muitos problemas com árias, partições no 5.5 (e erros confirmados) para usar essa combinação.
  • Realmente deve haver uma maneira melhor de redefinir o contador de sequência de log.
Glenn Plas
fonte
No MariaDB, você pode alterar rapidamente todas as tabelas usando USE INFORMATION_SCHEMA; SELECT CONCAT("ALTER TABLE `", TABLE_SCHEMA,"`.`", TABLE_NAME, "` REBUILD PARTITION ALL;") AS MySQLCMD AS MySQLCMD FROM TABLES;(fonte: dba.stackexchange.com/questions/35073/… ) e conectá- lo a um arquivo para ser executado como uma série de comandos.
Gwyneth Llewelyn