Sacdos' Lair

Geeks' tips & tricks

Erreurs du moteur de stockage InnoDB MySQL

Le moteur de stockage InnoDB du SGBDR MySQL est un très bon produit qui autorise notamment la gestion des clés étrangères.

Une base de données peut parfois accueillir des bases MyISAM traditionnelles (.frm, .myi…) et des bases InnoDB, mais, depuis sa version 5.5, MySQL a adopté ce dernier comme moteur de stockage par défaut.

Or, malgré tous ses bons côtés, InnoDB peut parfois faire sa mauvaise tête et empêcher purement et simplement MySQL de démarrer en vous abreuvant de son paradigme très personnel. La cause en est simple, une seule table corrompue suffit à le mettre en grève.

Dès lors, rien ne va plus, et MySQL vous met très rapidement dans la confidence :

  • ERROR 2013 When Connecting to Remote Server
  • ERROR 2003: Can’t connect to MySQL server on ‘localhost’
  • ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/tmp/mysql.sock’

Pour ne citer que ceux-là.

En configuration initiale, InnoDB tourne sur 3 fichiers stockés dans le dossier accueillant les tables :

  • ibdata1 qui recueille les données.
  • ib_logfile0, un premier fichier de log.
  • ib_logfile1, un second fichier de log.

Les fichiers de définition de table (.frm) sont, quant à eux, stockés directement dans les dossiers aux noms des bases. Si vous ne parvenez pas à localiser ces fichiers, n’hésitez pas à parcourir votre fichier de configuration mySQL (my.cnf) pour en extraire la substantifique moëlle.

Dans le cas de figure qui nous intéresse, plusieurs symptômes peuvent se présenter tour à tour, voire conjointement.

MySQL ne démarre pas et il vous insulte en binaire quand vous tenter de le lancer à la main :

#/etc/init.d/mysql start

Starting MySQL database server: mysqld.............failed !

Il s’y essaye en hexa :

MySQL Error : 2013 - Lost connection to MySQL server

Dernier comportement à signaler, il lui arrive également de se relancer de façon continue par le biais de mysqld_safe qui redémarre MySQL à chaque fois qu’il rencontre une erreur, ce qui vous laisse une chance sur 2 d’obtenir un accès base, et le reste du temps, de tirer un ticket erreur 2002, 2003 ou 2013 selon que votre requête est interrompue par un redémarrage intempestif, que MySQL ne trouve pas le socket ou qu’il ne trouve carrément pas le serveur.

Histoire de déterrer quelques informations supplémentaires, vous pouvez stopper toutes les instances de MySQL qui tourneraient sur l’infortuné malade via ces quelques manipulations :

# /etc/init.d/mysql stop

# killall -9 mysqld

# killall -9 mysqld_safe

# mysqladmin -uUSERNAME -p shutdown

Évidemment, on n’oublie pas de changer les majuscules, et un petit locate mysqladmin en cas de pépin. Et, pitié, évitez de noter votre mot de passe directement dans la commande…

Une fois que vous êtes certain que MySQL est arrêté, toujours en ssh, tentez un…

# mysqld

…Et prenez le temps de lire le râle d’agonie de votre serveur. Si vous trouvez une glossolalie ressemblant à ce qui suit, vous êtes sur la bonne voie.

InnoDB: Database page corruption on disk or a failed
InnoDB: file read of page 1294396.
InnoDB: You may have to recover from a backup.
InnoDB: It is also possible that your operating
InnoDB: system has corrupted its own file cache
InnoDB: and rebooting your computer removes the
InnoDB: error.

En revanche, si vous récupérer une longue litanie de lignes identiques à celle qui suit, il y a de fortes chances pour que votre serveur MySQL tourne encore.

InnoDB: Unable to lock ./ibdata1, error: 11

Si tout va bien, vous allez pouvoir indiquer à MySQL de passer outre les quelques débordements InnoDB en ajoutant la ligne suivante dans la section [mysqld] de votre fichier my.cnf.

innodb_force_recovery = 4

Puis démarrez MySQL :

# /usr/local/bin/mysqld_safe &

Attention, nous allons faire un backup du contenu de la base pour le réinjecter dans une nouvelle version de cette dernière donc, pour éviter tout problème, passez vos applis en maintenance ou changez carrément le port sur lequel tourne MySQL (3306 par défaut) pour déstabiliser l’ennemi. Une fois vos précautions prises, on enregistre le contenu de la totalité des bases en local :

# mysqldump --force --compress --triggers --routines --create-options -uUSERNAME -p --all-databases > /usr/savedb.sql

(Attention à changer le USERNAME). Ce script peut prendre un certain temps à finir de tourner. Une fois que vous aurez récupéré la main, arrêtez à nouveau MySQL :

# mysqladmin -uUSERNAME -p shutdown

Et supprimez le dossier contenant vos tables. Bon, évidemment, quand on est un peu parano comme moi on le renomme et on le cache dans un coin. Un détail tout de même, assurez-vous de ne pas avoir enregistré votre dump MySQL dans le dossier que vous effacez…

Puis recréez le dossier (adaptez le chemin et le nom du fichier en fonction de votre config, hein, pas de blague), donnez-lui les bonnes permissions et lancer le script d’initialisation MySQL :

# mkdir /usr/local/mysql-data
# chown -R mysql:mysql /usr/local/mysql-data
# /usr/bin/mysql_install_db
# chown -R mysql:mysql /usr/local/mysql-data

Enfin éditez votre fichier de configuration my.cnf et supprimez ou commentez la ligne salvatrice : innodb_force_recovery et relancez MySQL.

# /usr/local/bin/mysqld_safe &

Réinjectez vos données dans votre nouvelle base toute neuve…

# mysql -uroot --compress < /usr/savedb.sql

…et rechargez les privilèges !

# mysqladmin -uroot flush-privileges

That’s All Folks !

Si toutefois votre souci provenait d’une table MyISAM, tentez plutôt ça :

# mysqlcheck --all-databases -uUSERNAME -p -r

posted by sacdos in MySQL,Non classé and have No Comments

Place your comment

Please fill your data and comment below.
Name
Email
Website
Your comment