web-dev-qa-db-fra.com

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

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 à accélérer 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.

16
IcarusNM

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: le but 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_logfile 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 sous junk.pl.
  3. Exécutez junk.pl data1, et junk.pl data2, et junk.pl data, etc. tout à la fois, pour autant de cœurs de processeur comme votre serveur de base de données, pour commencer. Ouvrez plusieurs shells et encapsulez chaque exécution 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 divers innodb tampons augmentés par défaut. Assaisonner selon l'envie. Comme toujours, regardez mysqld.log dans une seule fenêtre.

10
IcarusNM

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écutez reset master; sur le maître (Zaps Binary Logs)
  • Étape 02: service mysql stop sur le maître
  • Étape 03: service mysql stop sur l'esclave
  • Étape 04: rsync/var/lib/mysql du maître à l'esclave
  • Étape 05: service mysql start sur 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-start sur 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écutez reset master; sur le maître (Zaps Binary Logs)
  • Étape 02: service mysql stop sur 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 stop sur le maître
  • Étape 06: rsync/var/lib/mysql du maître à l'esclave
  • Étape 07: service mysql start sur 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-start sur 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.

5
RolandoMySQLDBA

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 et couvert 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 Vanilla 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 un moyen lent pour 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 qu'il y en a une pour chaque définition de partition qu'elle ouvre avec des problèmes de compteur. Presque roulé aujourd'hui sur le comptoir 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.
2
Glenn Plas