Une meilleure façon de sortir du journal MySQL InnoDB «à l'avenir»?

16

J'ai cette erreur InnoDB dans MySQL 5.0. Mysqld a été arrêté proprement, mais j'ai réussi à perdre ib_logfile0 & ib_logfile1 par la suite. Maintenant, après un démarrage propre, InnoDB a fait sa «récupération après incident». J'ai parcouru l'entreprise innodb_force_recovery = 4, réparé une table MyISAM bloquée, et maintenant la réplication est prête à fonctionner, à part cela. Un grand nombre s'est engagé:

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.

C'est sur un serveur esclave. L'erreur ci-dessus crache par centaines. J'ai trouvé cette réponse: "insérer et supprimer> 64 Go de données, afin que le numéro de séquence du journal soit suffisamment gonflé".

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

Ce nombre magique de 64 Go vient de 4 Go * 16 où le journal de l'innodb de ce type "numéro majeur" devait passer de 0 à 15. Le mien passe de 70 à 111 = 164 Go. Cela prendra 5 jours. Je vais continuer à travailler sur l'accélération de mon script et à l'exécuter en parallèle pour accélérer cela. En attendant, j'espère que quelqu'un d'autre aura une meilleure réponse. C'est idiot.

IcarusNM
la source
Une réponse prometteuse: "S'il s'agit d'un serveur esclave, la meilleure solution serait vraiment de déplacer la base de données de côté et d'installer un nouvel instantané à partir du maître." Malheureusement, il y a 20 000 tables dans 25 bases de données, un mélange de MyISAM et InnoDB, en production 24h / 24 et 7j / 7. Il faudrait trop de temps pour arrêter tout cela et effectuer une nouvelle réplication complète avant de redémarrer la réplication.
IcarusNM
4
J'ai maintenant cette machine à 8 cœurs à genoux dans une course inutile pour créer et supprimer 164 Go de données. La seule alternative que j'entends est de tout neutraliser sur cet esclave et de recommencer à zéro. Tout pour changer efficacement un numéro dans deux fichiers. Il y a sûrement un ingénieur InnoDB avec une astuce pro. Quelqu'un a-t-il déjà ouvert ib_logfile0 dans Emacs, trouvé le nombre magique en hexadécimal et vient-il de le changer?
IcarusNM
Voici un excellent article sur quelques façons de le faire. Percona est définitivement l'autorité sur MySQL. percona.com/blog/2013/09/11/…
jbrahy

Réponses:

10

C'était une situation assez rare. J'espère ne plus jamais y retourner, avec un InnoDB "le numéro de séquence du journal est dans le futur!" Erreur. En raison de mes détails particuliers, la reconstruction / restauration des données de mon serveur était un dernier recours. Quelques astuces pour aider étaient de bonnes idées, mais à la fin, j'ai décidé de continuer à améliorer mon script Perl pour jouer à ce jeu stupide et à faire autant de concerts / heure que possible. Bon sang, c'est un bon test de résistance du système.

N'oubliez pas: l'objectif est d'augmenter un seul compteur ("numéro de séquence de journal") qui est stocké quelque part dans les en-têtes de ib_logfile0 et ib_logfile1 . C'est pour simuler InnoDB afin qu'il ignore une déformation temporelle apparente et continue la vie. Mais personne ne sait comment modifier ce numéro. Ou s'ils le savent, personne ne parle.

Voici mon produit final. YMMV, mais l'utilisation de la fonction REPEAT de mysql pour générer les données en interne est très efficace.

 #!/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");

Ma recette suggérée:

  1. Créer une base de données «indésirable»
  2. Enregistrez le script perl ci - dessus junk.pl .
  3. Exécutez junk.pl data1 et junk.pl données2 , et junk.pl data3 , etc. à la fois, pour autant de cœurs de processeurs que votre serveur de base de données a, pour commencer. Ouvrez plusieurs coquilles et envelopper chaque série dans une boucle Bash: while true; do date; junk.pl dataX; done.

Regardez votre LSN grandir, peut-être dans une autre boucle:

 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

Le grand nombre est un INT 32 bits non signé qui se terminera à 4 Go, augmentant le plus petit nombre à chaque fois. Dans ce cas ci-dessus, il est simplement passé de 124 à 125. Votre objectif est caché dans le mysqld.log qui vous a envoyé Google pour cette solution ridicule en premier lieu. Une fois que vous avez franchi cette ligne d'arrivée, c'est tout! Sonnez les cornes! Relâchez les confettis!

Barre latérale: Cela a révélé un bogue intéressant dans mysqld 5.0 avec REPEAT: si vous passez à 20 Mo, il retourne un compteur interne et passe à ~ 96 Ko. Aucun avertissement ou erreur n'importe où. Je n'allais pas perdre de temps à retrouver ça. 10 Mo fonctionnent très bien. Si vous atteignez une autre limite, elle peut se plaindre. J'ai différents tampons innodb augmentés par défaut. Assaisonner selon l'envie. Comme toujours, regardez mysqld.log dans une seule fenêtre.

IcarusNM
la source
Découvrez ceci percona.com/blog/2013/09/11/…
Jonas Stensved
Merci Jonas; c'est intéressant. Je pense que je peux m'en tenir à ma méthode ci-dessus. Il montre l'utilisation de gdb contre le mysqld en cours d'exécution que je ne risquerais probablement jamais. Mais de bonnes informations là aussi.
IcarusNM
Pour une raison étrange, en utilisant MariaDB, je n'obtiens pas les numéros de séquence de journal «petit nombre [espace] grand nombre» - mais juste un «grand nombre», donc malheureusement cette méthode n'a pas fonctionné pour moi. Bien sûr, le journal est mis à jour, je ne sais pas quand m'arrêter!
Gwyneth Llewelyn
5

Vous avez trois (3) options:

OPTION 01: Effectuer la synchronisation du maître vers l'esclave (temps d'arrêt sur le maître)

  • Étape 01: Exécuter reset master;sur le maître (journaux binaires Zaps)
  • Étape 02: service mysql stopsur le maître
  • Étape 03: service mysql stopsur l'esclave
  • Étape 04: rsync / var / lib / mysql du maître à l'esclave
  • Étape 05: service mysql startsur le maître
  • Étape 06: utilisez le premier journal binaire sur le maître comme journal pour démarrer la réplication. Utilisez la taille de fichier de ce journal comme position de démarrage de la réplication
  • Étape 07: service mysql stop --skip-slave-startsur l'esclave
  • Étape 08: Exécutez la commande CHANGE MASTER TO pour configurer la réplication à partir du journal et de la position déterminée à l'étape 06
  • Étape 09: exécutez start slave;sur l'esclave et laissez la réplication rattraper

OPTION 02: Effectuer la synchronisation du maître vers l'esclave (temps d'arrêt minimal sur le maître)

  • Étape 01: Exécuter reset master;sur le maître (journaux binaires Zaps)
  • Étape 02: service mysql stopsur l'esclave
  • Étape 03: rsync / var / lib / mysql du maître à l'esclave
  • Étape 04: répétez l'étape 03 jusqu'à ce que deux rsync consécutifs prennent le même temps
  • Étape 05: service mysql stopsur le maître
  • Étape 06: rsync / var / lib / mysql du maître à l'esclave
  • Étape 07: service mysql startsur le maître
  • Étape 08: utilisez le premier journal binaire sur le maître comme journal pour démarrer la réplication. Utilisez la taille de fichier de ce journal comme position de démarrage de la réplication
  • Étape 09: service mysql stop --skip-slave-startsur l'esclave
  • Étape 10: Exécutez la commande CHANGE MASTER TO pour configurer la réplication à partir du journal et de la position déterminée à l'étape 08
  • Étape 11: exécutez start slave;sur l'esclave et laissez la réplication rattraper

OPTION 03: utilisez XtraBackup

Cet outil logiciel fera non seulement une copie non importune d'un maître en cours d'exécution, mais créera également pour vous les ib_logfiles correspondants. Vous devrez configurer la réplication

J'ai déjà posté sur StackExchange à ce sujet

J'ai fait ces choses plusieurs fois pour la société d'hébergement Web de mon employeur. Un client avait 3,7 To pour se déplacer et cela a pris environ 16 heures. 64 Go est très petit en comparaison.

RolandoMySQLDBA
la source
Dans OPTION 02 Étape 05, vous dites de démarrer le maître. Quand a-t-il été arrêté? Rsync sur un maître en direct est courageux. Je suis impressionné. Et heureusement, j'utilise innodb_file_per_table. Mais finalement, vous devez mordre la balle et arrêter le maître assez longtemps pour qu'une dernière rsync s'exécute avant de démarrer la réplication. C'est une possibilité à laquelle je peux recourir, mais c'est un SGBD très actif. Et je vais regarder XtraBackup pour mes informations.
IcarusNM
@IcarusNM: Ah, faute de frappe. Je l'ai corrigé. Je vous remercie !!!
RolandoMySQLDBA
L'OPTION 02 pourrait probablement encore utiliser certains travaux. Par exemple, vous devriez faire l'étape 2 avant l'étape 1. Vous voulez probablement un RESET SLAVE quelque part. Typo à l'étape 4. Et vous dites "premier journal binaire" à l'étape 5 mais vous voulez vraiment dire "seulement" ou "dernier" journal binaire. Et vous devez utiliser mysqlbinlog pour vérifier la position des journaux, pas la taille du fichier. Et tout cela ne fonctionnera toujours que si vous arrêtez le maître à un moment donné. Baser une position / heure de journal sur le moment où une synchronisation est terminée est au mieux risqué.
IcarusNM
Je fais OPTION 2 depuis 4 ans avec des clients DB Hosting qui ont des données dans la gamme TeraByte. Il fonctionne à chaque fois sur un serveur en cours d'exécution. La seule vraie erreur que vous pourriez faire est sur l'esclave. Cette erreur serait de savoir si la réplication a été configurée correctement ou non. De plus, RESET SLAVEest utile, surtout si vous avez accumulé de nombreux Go de journaux de relais. Après le processus rsync et le rétablissement de la réplication, n'oubliez pas que la commande CHANGE MASTER TO effacera également les journaux de relais pour vous également.
RolandoMySQLDBA
mmm ... étrange. j'ai configuré mon esclave en utilisant xtrabackup (comme toujours) et j'ai toujours ces erreurs de journal (percona mysql 5.5.x) ... semble qu'il y ait eu quelque chose de mal sur cet esclave et je dois le faire à nouveau.
harald
2

J'ai découvert qu'il existe peut-être un moyen plus efficace de résoudre ce problème en travaillant sur des tables partitionnées. J'ai dû supprimer des partitions il y a quelques années et j'ai dû en ajouter pour 2014. Presque toutes les partitions signalent cette erreur, donc aussi les anciennes. Accident très méchant.

Donc, tout en laissant tomber l'ancien et en utilisant REORGANIZE de la partition MAXVALUE (la dernière), cela créera de nouveaux fichiers qui sont ok, donc je reçois de moins en moins d'avertissements. En attendant, cela aide à incrémenter le compteur de séquence de journaux, donc je n'ai pas besoin d'insérer de fausses données. J'ai ce qui se passe sur un serveur maître btw ...

Donc ça:

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;

Et ça:

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)

Cela supprimera efficacement chaque partition dans la modification et la recréera avec une copie temporaire du contenu de ce qui s'y trouvait. Vous pouvez le faire par table si vous le souhaitez, mon application permet que cela se produise, donc pas besoin de vous soucier des sauvegardes synchronisées, etc.

Maintenant, pour le reste de la table, puisque je n'ai pas touché toutes les partitions dans le processus, certaines se retrouveront avec l'avertissement de séquence de journal, pour celles qui sont cassées mais couvertes par cette action de réorganisation, je vais probablement exécuter ceci:

ALTER TABLE Events REBUILD PARTITION p0, p1;

ou ça

ALTER TABLE Events OPTIMIZE PARTITION p0, p1;

Donc, cela m'a fait penser, vous pouvez le faire avec des tables simples, ajouter temporairement des partitions par hachage et les supprimer plus tard (ou les conserver, je peux fortement recommander des partitions).

J'utilise cependant mariadb, pas mysql (donc XtraDB)

Peut-être que cela aide quelqu'un. Je le dirige toujours, jusqu'ici tout va bien. Changer d'ENGINE semble faire le travail aussi, donc je le ramène entre MyIsam et eux vers InnoDB.

C'est assez logique, si vous changez ENGINE, la table disparaît de innodb, donc ce ne sera plus un problème.

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

cela semble fonctionner ici. Je peux confirmer quelques éléments sur les tables partitionnées:

  • ALTER TABLE xyz ENGINE = InnoDB est très lent, pour Aria (mariadb) deux fois plus rapide, mais en général une manière lente d'incrémenter le compteur de séquence de journaux
  • ALTER TABLE xyz REBUILD PARTITION ALL est le moyen le plus rapide de «réparer» les tables et d'aider à incrémenter le compteur
  • ALTER TABLE xyz ANALYZE PARTITION ALL est lent comparé à l'ancien et ne réécrit pas les partitions qui s'avèrent correctes. REBUILD assure une réécriture dans un schéma de table temporaire.

J'ai utilisé les derniers sur plusieurs tables. Les avertissements se produisent lorsqu'il essaie d'ouvrir les fichiers et il y en a une pour chaque définition de partition qu'elle ouvre avec des problèmes de compteur. Presque roulé sur le comptoir aujourd'hui pour les dernières tables. Je pense qu'une fois que tout est traité, il faut vider les journaux binaires.

mise à jour : je peux conclure quelques choses maintenant j'ai réussi à régler ce problème.

  • Mon plantage a été causé par la réorganisation des partitions sur une table au format Aria (MariaDB).
  • (pour moi) faire une reconstruction des partitions a fonctionné le mieux et le plus rapidement pour obtenir le compteur de séquence. La modification du moteur est lente et vous devez le faire deux fois pour affecter innodb. la modification de innoDB est assez lente par rapport à MyIsam ou Aria.
  • J'ai mis à niveau vers MariaDB 5.3 et non vers 5.5 (était: 5.2) et cela fonctionne bien. Je pense qu'il y a beaucoup trop de problèmes avec aria, les partitions en 5.5 (et les bugs confirmés) pour utiliser cette combinaison.
  • Il devrait vraiment y avoir un meilleur moyen de réinitialiser le compteur de séquence de journaux.
Glenn Plas
la source
Sous MariaDB, vous pouvez rapidement modifier toutes les tables à l'aide de USE INFORMATION_SCHEMA; SELECT CONCAT("ALTER TABLE `", TABLE_SCHEMA,"`.`", TABLE_NAME, "` REBUILD PARTITION ALL;") AS MySQLCMD AS MySQLCMD FROM TABLES;(source: dba.stackexchange.com/questions/35073/… ) et les insérer dans un fichier à exécuter sous la forme d'une série de commandes.
Gwyneth Llewelyn