Mysql : Maitre/esclave (2016)

Mysql : mise en cluster maître/esclave. 
Vous disposez d'une belle application fonctionnant sur une non moins belle base de données Mysql qui contient tout ce qui est nécessaire à votre application. 
Mais que se passera-t-il si votre base est indisponible (crash base, disque ayant rendu l'âme, prise de pied dans la prise de courant ....) ? 
Votre belle application ne fonctionnera plus du tout ... 
La solution : Clusteriser votre base de données en mode maître/esclave. 
Oui, mais ma base existe déjà, comment faire ? Je n'ai pas envie de "dumper" toutes mes tables .... !!! et de les recharger. 
C'est cette histoire que je vais vous conter. 
Vous ne touchez pas à votre serveur original (il marche, ne pas le déranger), et vous préparez une merveilleuse machine, identique pour bien faire, et faites-y une installation complète de Mysql de préférence dans la même version, ici c'est du 5.6 ! Cela marche aussi très bien avec MariaDB. 
Si la structure des répertoires de DATA n'est pas "standard" il vaut mieux refaire à l'identique, cela simplifiera toute la maintenance. 
Un peu de vocabulaire pour la suite :

  • Serveur1 : votre serveur "actuel"
  • Serveur2 : le petit nouveau.

L'opération consiste à :

  • Créer les utilisateurs nécessaires à la réplication (Serveur1).
  • Stopper Mysql sur le Serveur1
  • Sauvegarder l'intégralité des fichiers de la BDD, si vous utilisez LVM (ou BTRFS) vous pouvez faire un snapshot du support disque de votre base, et la relancer immédiatement. Sinon "tar" fonctionne encore ...
  • Modifier le fichier de config de Serveur1
  • Stopper Mysql sur Serveur2, et bien nettoyer les répertoires de Mysql, y compris les fichiers de "/var/log/mysql"
  • Restaurer les données de Serveur1 sur Serveur2.
  • Détruire un petit fichier sur Serveur2 (/var/lib/mysql/auto.cnf)
  • Reparamétrer Serveur2 en esclave, et en "read-only", c'est plus prudent.
  • Redémarrer Serveur2

Note : Il existe des moyens de faire une sauvegarde "on line" ce qui évite de stopper le serveur, mais dans ce cas il faut enregistrer la position dans le "binlog" pour permettre à l'esclave de repartir juste après la dernière transaction enregistrée.

Vous pouvez alors passer Serveur2 en mode "esclave" et Serveur2 sera maintenu à jour par rapport à Serveur1.

Un peu de détail pour arriver à ce Nirvana : 
1) Créer les utilisateurs pour la réplication sur Serveur1 :

* 
    Users pour replication 
*/ 
create user         'replic_usr'@'mysql1'       identified by 'Mon_Secret'; 
grant all on *.* to     'replic_usr'@'mysql1'       with grant option;

create user         'replic_usr'@'192.168.2.62' identified by 'Mon_Secret'; 
grant all on *.* to     'replic_usr'@'192.168.2.62' with grant option; 
/* 
*/ 
create user         'replic_usr'@'mysql2'       identified by 'Mon_Secret'; 
grant all on *.* to     'replic_usr'@'mysql2'       with grant option;

create user         'replic_usr'@'192.168.2.63' identified by 'Mon_Secret'; 
grant all on *.* to     'replic_usr'@'192.168.2.63' with grant option;

Note : 
Vous avez un Mysql installé sur Serveur2, vérifiez que le user "replic_usr" peut bien se connecter sur Serveur1 : 
mysql -user=replic_usr --password=Mon_Secret -D mysql 
Si tout va bien vous pouvez alors stopper Mysql sur Serveur2. 
2) Une fois ceci réalisé stopper Mysql sur serveur 1. 
Sauvegardez /var/lib/mysql et ici, en plus /DATA/D1 et /DATA/D2 pour compliquer un peu.

3) Pendant ce temps modifier votre fichier "mysqld.cnf" et ajoutez-y  :

### pour Master 
server-id               = 1 
log-bin                 = mysql-bin 
binlog-format           = MIXED 
log-slave-updates       = true 
gtid-mode               = on 
enforce-gtid-consistency= on 
master-info-repository  = table 
report-host             = mysql1

4) Stoppez Mysql sur Serveur2. 
5) Transportez vos copies sur Serveur2 et restaurez les "en place". 
6) Supprimer le fichier "auto.cnf" dans /var/lib/mysql. 
6) Modifiez le fichier "mysqld.cnf", comme pour Serveur1 sauf "server-id" et "report-host":

### pour Slave   
server-id                = 2 
read-only                = 1 
log-bin                  = mysql-bin 
binlog-format            = MIXED 
log-slave-updates        = true 
gtid-mode                = on 
enforce-gtid-consistency = 1 
master-info-repository   = table 
report-host              = mysql2

7) C'est presque fini : 
Redémarrez Mysql sur Serveur1 et verifiez dans le fichier "error.log" la présence du message : 
/usr/sbin/mysqld: ready for connections. 
Passons maintenant au Serveur2 : 
Nettoyer certains fichier que vous venez de restaurer dans /var/lib/mysql : 
- mysql-bin* 
Son fichier de configuration est correct, bien vérifier que le fichier "auto.cnf" (il contient un UUID) "/var/lib/mysql/auto.cnf" est effacé avant de redémarrer le serveur qui va s'empresser de le recréer avec un nouvel "UUID" différent de celui de Serveur1. 
On peut alors "asservir" notre futur esclave :

mysql -u root -p -D Le_mot_de_passe_qui_va_bien 
change MASTER  to MASTER_USER='replic_usr', 
    MASTER_PASSWORD='Mon_Secret', 
    MASTER_HOST='192.168.2.62';

\q

Qui devrait répondre gentiment : 
Query OK, 0 rows affected, 2 warnings (0,31 sec) 
Puis : 
start slave; 
qui répond (gentiment lui aussi) : 
Query OK, 0 rows affected (0,11 sec)

Verifications : 
Nos données sont-elles toujours sur le maître :

mysql> show tables; 
+--------------------+ 
| Tables_in_test_del | 
+--------------------+ 
| ANAL_FIR_ARC       | 
| ANAL_FIR_TEST      | 
| TEST_LOG           | 
+--------------------+ 
3 rows in set (0,00 sec)

Et sur l'esclave ?

mysql> show tables; 
+--------------------+ 
| Tables_in_test_del | 
+--------------------+ 
| ANAL_FIR_ARC       | 
| ANAL_FIR_TEST      | 
| TEST_LOG           | 
+--------------------+ 
3 rows in set (0,00 sec)

Rien ne s'est perdu en route, nos petites données sont maintenant en sécurité ! 
Maintenant créons une table sur le maître :

create table toto ( zone varchar(32) ); 
Query OK, 0 rows affected (0,36 sec) 
mysql> show tables; 
+--------------------+ 
| Tables_in_test_del | 
+--------------------+ 
| ANAL_FIR_ARC       | 
| ANAL_FIR_TEST      | 
| TEST_LOG           | 
| toto               | 
+--------------------+ 
4 rows in set (0,00 sec)

Et sur l'esclave :

mysql> sow tables; 
+--------------------+ 
| Tables_in_test_del | 
+--------------------+ 
| ANAL_FIR_ARC       | 
| ANAL_FIR_TEST      | 
| TEST_LOG           | 
| toto               | 
+--------------------+ 
4 rows in set (0,00 sec)

Allez on s'en refait un coup, sur le maître :

mysql> insert into toto (zone) values ('Ah oui, comme cela est bon'); 
commit;

Et sur l'esclave :

mysql> select * from toto; 
+----------------------------+ 
| zone                       | 
+----------------------------+ 
| Ah oui, comme cela est bon | 
+----------------------------+ 
1 row in set (0,00 sec)


A bientôt pour la suite de ces passionnantes aventures dans le monde de Mysql.