MySQL Cluster : Problème de réplication

Contexte

Un slave MySQL tourne sur mysqld-04 et réplique en temps réel les modifications apportées au Cluster. Ce slave peut au choix utiliser comme master mysqld-01 ou mysqld-04 (sur mysqld-04 il y a donc le slave + le master qui tournent).

mysqld-04 est configuré comme suit slave port 3306 et master port 3307.

Le problème de désynchronisation vient du fait que la base de données du slave et celle du cluster ont des très légères différences (au niveau des procédures stockées). Si une modification est faite sur cette zone sur le cluster, lorsque le slave tentera de la répliquer, il ne trouvera pas la zone à modifier dans sa propre base et stoppera la réplication. Il faudra alors sauter l’erreur et relancer la réplication.

Oui je sais c’est pas courant de mettre un master avec un slave mais bon ça permet de voir un cas particulier qui est le multi mysqld.

Il y a aussi 2 data nodes et 2 api node mais on s’en fout, ils tournent tout seul.

Récupération de l’erreur

Sur mysqld-04, se connecter au slave et identifier le master et l’erreur au moment de la coupure :

mysql -p
mysql> show slave status \G

Type d’erreurs :

The incident LOST_EVENTS occured on the master. Message: error writing to the binary log ⇒ voir Switch Master

Error ‘Unknown storage engine ‘ndbcluster » on query. Default database: ‘XXX’. Query: ‘XXX’ ⇒ voir Skip Error

Switch Master

Le master qui a planté est Mysql-01

Il faut relancer la réplication sur un autre master. On récupère le dernier epoch sur le slave mysqld-04

mysql -u root -p

mysql> SELECT @latest:=MAX(epoch) FROM mysql.ndb_apply_status;
+---------------------+
| @latest:=MAX(epoch) |
+---------------------+
|  292125486287421459 |
+---------------------+
1 row in set (0,00 sec)

Sur un autre noeud master, on récupère la position dans les binlogs ainsi que le nom du fichier correspondant à l’epoch récupéré plus haut (exemple avec le master de mysqld-04.On utilise la master socket on peut tout aussi bien utiliser l’host et le port.

mysql -S /var/lib/mysql_master/mysql_master.sock -p
mysql> SELECT @file:=SUBSTRING_INDEX(next_file, '/', -1), @pos:=next_position FROM mysql.ndb_binlog_index WHERE epoch  = 292125486287421459 ORDER BY epoch ASC LIMIT 1;
+--------------------------------------------+---------------------+
| @file:=SUBSTRING_INDEX(next_file, '/', -1) | @pos:=next_position |
+--------------------------------------------+---------------------+
| mysql-bin.001996                           |           688465217 |
+--------------------------------------------+---------------------+
1 row in set (0,00 sec)

Puis sur le slave, on change de master en précisant le binlog et la position récupérée plus haut (exemple avec le master de mysqld-04, attention que l’IP/port correspondent) :

mysql> stop slave;
Query OK, 0 rows affected (0,01 sec)
mysql> CHANGE MASTER TO MASTER_HOST='localhost', MASTER_PORT=3307, MASTER_USER='replication',
MASTER_PASSWORD='passwd_replication', MASTER_LOG_FILE='mysql-bin.001996', MASTER_LOG_POS=688465217 ;
Query OK, 0 rows affected, 2 warnings (0,01 sec)

On regarde les warnings avec

mysql>show warnings
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1759 | Sending passwords in plain text without SSL/TLS is extremely  insecure.                                                                                                                                         |
| Note  | 1760 | Storing MySQL user name or password information in the master.info repository is not secure and is therefore not recommended. Please see the MySQL Manual for more about this issue and possible alternatives. |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

On s’en balance.

Et on relance la réplication :

mysql> start slave;
Query OK, 0 rows affected (0,01 sec)

On vérifie que la réplication ait bien repris et que le slave rattrape son retard :

mysql> show slave status \G
      Seconds_Behind_Master: 2471
    ...
              Last_IO_Errno: 0
              Last_IO_Error: 
             Last_SQL_Errno: 0
             Last_SQL_Error: 

Skip Error

Saut de l’erreur, celle-ci n’étant pas critique.

Il se peut qu’il y est plusieurs erreurs mettre SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 5

Sur le serveur mysql slave :

mysql> SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
Query OK, 0 rows affected (0,01 sec)
mysql> start slave;
Query OK, 0 rows affected (0,01 sec)}}}

Suivi du bon rétablissement avec :

mysql> show slave status \G
      Seconds_Behind_Master: 2471
              Last_IO_Errno: 0
              Last_IO_Error: 
             Last_SQL_Errno: 0
             Last_SQL_Error: 
mysql> show slave status \G
      Seconds_Behind_Master: 0
              Last_IO_Errno: 0
              Last_IO_Error: 
             Last_SQL_Errno: 0
             Last_SQL_Error: 

Incident réplication binlog Master

L’alerte en question est MySQL Cluster Replication : Master binlog interrupted mysqld-04

Contrairement aux erreurs ci-dessus, celle-ci n’est détectée que par les alertes du système de monitoring En effet, un show slave status ne remonte aucune erreur.

Pour confirmer l’erreur, dans un process list, on voit que l’instance master de mysqld-04 est en attente: Ceci n’est cependant pas obligatoire, car cela va dépendre de ce que le master foutait avant de se toler.

mysql> show processlist;
+--------+-------------+-----------+------+---------+---------+----------------------------------------------------------------------
| Id     | User        | Host      | db   | Command | Time    | State                                                                       | Info             |
+--------+-------------+-----------+------+---------+---------+----------------------------------------------------------------------
|      1 | system user |           |      | Daemon  |   34476 | Waiting for schema epoch                                                    | NULL             |
|      3 | system user |   | NULL | Connect | 2073040 | Slave has read all relay log; waiting for the slave I/O thread to update it 
| NULL             |
| 220997 | root        | localhost | NULL | Query   |       0 | init                                                                        | show processlist |
+--------+-------------+-----------+------+---------+---------+----------------------------------------------------------

On peut également constater que les dernier epoch entre mysqld-04 et mysqld-01 sont différents, ce qui sert également à confirmer l’erreur:

Sur Mysqld-04, on utilise la socket Mysql pour se connecter afin d’être sur le master.

mysql -S /var/lib/mysql_master/mysql_master.sock -p

mysql> SELECT @file:=SUBSTRING_INDEX(next_file, '/', -1), @pos:=next_position, 
epoch FROM mysql.ndb_binlog_index ORDER BY epoch DESC LIMIT 1;
+--------------------------------------------+---------------------+--------------------+
| @file:=SUBSTRING_INDEX(next_file, '/', -1) | @pos:=next_position | epoch              |
+--------------------------------------------+---------------------+--------------------+
| mysql-bin.002514                           |           418531181 | 310467702470737931 |
+--------------------------------------------+---------------------+--------------------+

Et sur mysqld-01

mysql -p
mysql> SELECT @file:=SUBSTRING_INDEX(next_file, '/', -1), @pos:=next_position, 
epoch FROM mysql.ndb_binlog_index ORDER BY epoch DESC LIMIT 1;

+--------------------------------------------+---------------------+--------------------+
| @file:=SUBSTRING_INDEX(next_file, '/', -1) | @pos:=next_position | epoch              |
+--------------------------------------------+---------------------+--------------------+
| mysql-bin.002645                           |           118810291 | 310541124936663043 |
+--------------------------------------------+---------------------+--------------------+

Avant de procéder au redémarrage de l’instance master de mysqld-04, il faut effectuer un changement de master du slave sur mysqld-01. Voir change master au dessus.

Une fois le changement effectué, on peut procéder au redémarrage, pour connaitre l’id de l’instance visée, se rendre dans le fichier my.cnf souvent dans /etc.

mysqld_multi stop 1

Si les instances ne s’arrêtent pas, on kill les processus (Attention à bien tuer les processus de l’instance master !!!)

ps faux

root     24522  0.0  0.0   9980   328 ?        S     2014   0:00 /bin/sh /usr/bin/mysqld_safe --skip-slave-start   --default-storage-engine=innodb --explicit_defaults_for_t 

mysql    26110  210 37.1 11110332 9153496 ?    Sl    2014 1133795:12  \_ /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql/ --plugin-dir=/usr/lib64/mysql/plugin --

root     11520  0.0  0.0  10200   340 ?        S     2014   0:00 /bin/sh /usr/bin/mysqld_safe --skip-innodb --default-storage-engine=NDBCLUSTER --default_tmp_storage_engi

mysql    18226  2.1  1.2 706924 311516 ?       Sl   Apr14 755:37  \_ /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql_master/ --plugin-dir=/usr/lib64/mysql/plugin
kill -9 11520 18226

Dans les logs, on constate le bon redémarrage de l’instance :

2015-05-08 10:15:39 18226 [Note] /usr/sbin/mysqld: Normal shutdown
2015-05-08 10:15:39 18226 [Note] Giving 2 client threads a chance to die gracefully
2015-05-08 10:15:39 18226 [Note] Event Scheduler: Purging the queue. 0 events
2015-05-08 10:15:39 18226 [Note] Shutting down slave threads
2015-05-08 10:15:39 18226 [Note] Error reading relay log event: slave SQL thread was killed
2015-05-08 10:15:41 18226 [Note] Forcefully disconnecting 1 remaining clients
2015-05-08 10:17:52 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql_master/
2015-05-08 10:17:53 16055 [Note] Plugin 'InnoDB' is disabled.
2015-05-08 10:17:53 16055 [Note] Plugin 'FEDERATED' is disabled.
2015-05-08 10:17:53 16055 [Note] NDB: NodeID is 171, management server 'xxx.xxx.xxx.xxx:1186'
2015-05-08 10:17:54 16055 [Note] NDB[0]: NodeID: 171, all storage nodes connected
2015-05-08 10:17:54 16055 [Note] NDB[1]: NodeID: 170, all storage nodes connected
2015-05-08 10:17:54 16055 [Note] Starting Cluster Binlog Thread
2015-05-08 10:17:54 16055 [Note] Recovering after a crash using mysql-bin

Rapidement, le master récupère son retard et on a de nouveau le même epoch sur les 2 serveurs.

Corruption de la base ndb_binlog_index

le master est mysqld-01, un problème de réplication master se produit dessus. Nous voulons changer de master sur le slave pour passer sur mysql-04.

Mais la une surprise attends :

mysql> SELECT @file:=SUBSTRING_INDEX(next_file, '/', -1), @pos:=next_position 
FROM mysql.ndb_binlog_index WHERE epoch = 341260363125227536 ORDER BY epoch ASC LIMIT 1;

retourne

ERROR 145 (HY000): Table './mysql/ndb_binlog_index' is marked as crashed and should be repaired

Pour s’en sortir.

repair table mysql.ndb_binlog_index;

ou en fait préférer celle-ci pour le ne pas altérer les binlogs

REPAIR NO_WRITE_TO_BINLOG TABLE mysql.ndb_binlog_index;