Mysql resynchronisation / replication

De BlaxWiki
Révision datée du 15 janvier 2021 à 11:42 par 127.0.0.1 (discussion)
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à la navigationAller à la recherche


Mise en place réplication

http://dev.mysql.com/doc/refman/5.0/fr/replication-howto.html

Configuration

Pour mettre en place la synchronisation, il faut 2 serveurs MySQL qui ont accès l'un a l'autre (en pratique le slave doit avoir accès au master uniquement). Il faut de plus créer,
 sur le master, un user spécifique a la réplication :

GRANT REPLICATION SLAVE ON *.* TO 'replicadmin'@'IP du slave' IDENTIFIED BY 'password';

# Dans le fichier my.cnf du master il faut ces lignes :
server-id = 1 (indispensable)
log_bin = /var/log/mysql/mysql-bin.log(indispensable) 
expire_logs_days = 30 (indispensable pour purger les logs binaires au bout de x jours)
relay-log = master-relay-bin (si on a des warning au restart de mysql, pas toujours nécessaire)
relay-log-index = master-relay-bin.index (si on a des warning au restart de mysql, pas toujours nécessaire)

# Dans le fichier my.cnf du slave il faut uniquement (dans le cas d'un mysql < 5.5) :
server-id = 2 (indispensable)
master-host = <ip_master> (indispensable)
master-user = <user_replication> (indispensable)
master-password = <password_user> (indispensable)
master-port = <port_master> (indispensable)
relay-log = slave-relay-bin (si on a des warning au restart de mysql, pas toujours nécessaire)
relay-log-index = slave-relay-bin.index ((si on a des warning au restart de mysql, pas toujours nécessaire)

# 1ere synchronisation

La synchronisation ne peut se faire a partir de rien, il faut que les informations du slave soit l'exacte replique du master au demarrage (meme comptes, meme password, même 
database/tables) Il faut donc copier le dossier mysql du master vers le slave, une fois copie, il est faut lancer le master, puis le slave qui va commencer la synchro. Il est 
possible de n'avoir qu'une synchronisation de table ou de base ou d'avoir une synchronisation croisee (master/master). Cela n'etant pas standard, cela n'est pas documente ici. 

Mysql 5.5 et supérieur

# Master
Créer, un utilisateur spécifique à la réplication :mysql> GRANT REPLICATION SLAVE ON *.* TO 'replicadmin'@'IP du slave' IDENTIFIED BY 'password';

Arrêter MySQL & Éditer le my.cnf et ajouter les lignes : 
server-id = 1
log-bin = /var/log/mysql/mysql-bin.log

Faire un tar.gz du répertoire de données de MySQL (/opt/data/mysql), on le copiera sur le slave plus tard. Redémarrer MySQL, et lancer la commande SHOW MASTER STATUS afin d'avoir
la position au moment du tar

# Slave
Arrêter MySQL, détarer dans /opt/data le tar.gz préalablement fait sur le master.
Ajouter au my.cnf : 
server-id=2

!!! Sur les debian, le mot de passe root mysql est aussi encrypté dans /etc/mysql/debian.cnf, il faut editer ce fichier sur le slave et mettre le meme mot de passe que sur le master !!!

Démarrer Mysql, se connecter à mysql : 
CHANGE MASTER TO MASTER_HOST='ip_du_master', MASTER_USER='replicadmin', MASTER_PASSWORD='passwd_replicadmin', MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=654;
start slave;

Les deux derniers paramètres se récupèrent sur le master après avoir fait le tar.gz. Pour les récupérer, se connecter sur le MySQL du master, et utiliser les commandes suivante :

# Met en read only les bases / tables
mysql> FLUSH TABLES WITH READ LOCK;
mysql> SHOW MASTER STATUS;
## Enleve le read only, on peut aussi faire set @@global.read_only=1;
mysql> UNLOCK TABLES;

Vérification

mysql> show slave status\G;

# Master Host etant l'ip du maitre
# Master User le compte utilise pour la replication
# Master_Log_File: le fichier de transaction en cours du maitre
# Relay_Log_File : le fichier de transaction en cours du thread I/O du slave
# Relay_Master_Log_File : fichier de transaction en cours du thread SQL du slave
# Le thread I/O s'occupe de recuperer en local les transactions du maitre, il ne met pas a jour la base mysql du slave
# Le thread SQL s'occupe de relire le fichier de transaction local cree par le thread I/O pour le rejouer en local
# Seconds_Behind_Master (mysql 5.x uniquement) : le nombre de seconde de retard par rapport au master 

Gestion des erreurs

Chaque thread peut etre arrete separement, sur le slave un start slave IO_THREAD permet de lancer le thread IO (qui gere la communication avec le master), tandis que start slave SQL_THREAD permet de lancer le SQL (qui gere l'integration des requetes dans la base locale). Un start slave seul lance les deux. Leur status est disponible dans le show status :

   * Slave_IO_Running: Yes
   * Slave_SQL_Running: Yes 

Si les threads sont arrete cela peut etre une demande manuelle, ou bien en raison d'une erreur.

Slave_SQL_Running:NO

1. query '...' partially completed on the master and was aborted

Cela se presente de cette maniere :
      Last_error: query 'insert into LOG_DOWNLOAD_SOUND values (, '2003-12-02 14:17:47', '5461887927737677039125448195', 'ok', , '7978', '2', '2', 'Panasonic-GAD87/A53', , )' 
partially completed on the master and was aborted. There is a chance that your master is inconsistent at this point. If you are sure that your master is ok, run this query manually 
on the slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; SLAVE START; . 

Parfois la base implique est indique, parfois elle ne l'est pas, il faut donc retrouver la transaction complete ayant entraine le probleme avant de pouvoir re lancer la 
synchronisation.

Il faut donc aller sur le master et lancer la commande suivante : SHOW BINLOG EVENTS in '<Relay_Master_Log_File>' FROM <Exec_master_log_pos>, cela fournira une ligne indiquant la 
base implique. Il suffira de faire un use <base>, puis la transaction en erreur, puis enfin SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; SLAVE START;

Il faut ensuite verifier que la synchronisation se fait bien et qu'aucune autre erreur n'apparait. Si c'est le cas, refaire le skip counter suivi d'un slave start :  ATTENTION : Il 
ne faut pas mettre une autre valeur que 1 dans le sql_slave_skip_counter, car cela peut entrainer la non application d'une requete qui potentiellement peut ne pas etre en erreur. Il 
faut faire un slave start systematiquement apres le SET GLOBAL pour que la valeur soit prise en compte

En cas d'erreur lie a un crash du master, 2 cas peuvent alors survenir, l'un est reparable, l'autre non.

    * Le fichier binlog du master est corrompu. Le slave indique que le binlog du master est corrompu. Il n'existe pas de solution pour resoudre le probleme, il faut repartir avec 
une synchro complete
      Le fichier binlog du master n'est pas corrompu mais incomplet. Le slave a donc une position plus recente que celle presente dans le fichier du master, il est donc arrete avec 
l'erreur suivante Client requested master to start replication from impossible position. Il faut donc indiquer au slave de repartir d'une position connue en recuperant la derniere 
position valide dans le binlog (mysqlbinlog <nomdufichierlog> |tail -5), et en la placant dans le fichier relay-log.info et master.info du slave apres avoir arrete mysql puis 
relancer le service 

2. Query '...' caused different errors on master and slave.

Cela indique generalement qu'une transaction effectue sur le master a echoue, mais que celle sur le slave a reussi. Generalement, la table sur le master est corrompu. Il suffit 
alors de reparer la table du master, si elle est toujours en erreur, et d'ignorer l'alerte en question (SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; SLAVE START;)

3. Error 'Duplicate entry (...)

Cette erreur indique qu'une tentative d'enregistrement dans une table a clef est effectue mais que la clef existe deja. Cela indique surtout une desynchronisation de la replication 
car le slave n'est la copie du master. Afin de tenter de rattraper au mieux la replication il faut :
    * Recuperer l'enregistrement en question sur le master
    * Verifier que l'enregistrement qui a echoue sur le slave correspond a l'entree du master
     o Si c'est le cas, supprimer l'enregistrement du slave et relancer le slave SANS faire de skip
     o Si ca n'est pas le cas, effectuer un skip du slave : SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE;  

Il faut ensuite verifier que la synchronisation se fait bien et qu'aucune autre erreur n'apparait. Si c'est le cas, recommencer la procedure.

ATTENTION : Il ne faut pas mettre une autre valeur que 1 dans le sql_slave_skip_counter, car cela peut entrainer la non application d'une requete qui potentiellement peut ne pas 
etre en erreur. Il faut faire un slave start systematiquement apres le SET GLOBAL pour que la valeur soit prise en compte

Attention, le fait d'avoir un duplicate entry n'est pas normal. Cela indique qu'un process a ecrit sur le slave en dehors de la replication. Cela laisse a supposer que le slave 
n'est plus l'exacte copie du master. Le client doit etre prevenu de ce fait dans le mail d'intervention. La solution n'est pas une resynchronisation complete mais eventuellement une 
recopie de la base/table impacte par la requete peut suffire.

4. Error 'Cannot delete or update a parent row: a foreign key constraint fails (...)

Cette erreur indique qu'une requete de modification ou de suppression n'a pu etre realisee en raison d'une contrainte lie a une clef etrangere. Plus simplement, l'enregistrement a 
une liaison avec un autre enregistrement. L'erreur indique que cette liaison n'existe plus sur le master (puisque la requete est passe), mais qu'elle existe toujours sur le slave. 
Il y a donc eu une precedente desynchronisation qui a garde la liaison ou l'enregistrement 'master'. Normalement, la synchronisation n'est donc plus garantie du fait de cette 
erreur. Elle ne peut arriver que si une mauvaise manipulation a ete effectuee auparavant (ie un skip qui n'aurait pas du etre fait), si la synchronisation initiale n'a pas ete 
realisee correctement ou si le slave a ete modifiee directement par une application. Effectuer un skip de cette erreur ne va qu'accentuer la difference entre le master et le slave. 
Il faut donc :
    * Valider l'absence de l'enregistrement lie sur le master (il faut voir le detail de la requete car la liaison peut etre sur n'importe quoi)
    * Supprimer manuellement l'enregistrement sur le slave
    * Relancer le slave SANS effectuer de skip
    * Prevenir le client (ou le CDP si il y en a un) de l'erreur et que celle ci doit provenir d'une requete effectuee en direct sur le slave et que donc la synchronisation n'est 
plus garantie. 

En dernier recours, Si vous êtes vraiment sur que vous pouvez deleter ou updater, malgrès la FK :
mysql> SET foreign_key_checks = 0; 
mysql> delete/update/...
mysql> SET foreign_key_checks = 1; 

Slave_IO_Running: NO

Log entry on master is longer than max_allowed_packet

Dans les LOGS erreur :
070313 19:38:18  Error reading packet from server: Packet too large - increase max_allowed_packet on this server (server_errno=1153)
070313 19:38:18  Log entry on master is longer than max_allowed_packet (1047552) on slave. If the entry is correct, restart the server with a higher value of max_allowed_packet

Il faut augmenter cette variable pour que la transaction passe

En console sur l'instance mysql en cause : SHOW GLOBAL VARIABLES LIKE 'max_allowed_packet' --> max_allowed_packet : 1047552
On la double par exemple : SET GLOBAL max_allowed_packet=2095104; On vérifie de nouveau avec la commande SHOW GLOBAL VARIABLES LIKE 'max_allowed_packet' --> max_allowed_packet : 
2095104

Ensuite on redémarre le slave : START SLAVE;

On vérifie que les IO tournent :
Slave_IO_Running:Yes
Slave_SQL_Running: Yes

Espace disque

Master : Sur les master, l'espace disque se remplit de fichier bin-logs. la commande purge master logs permet de supprimer les fichiers jusqu'a une date ou un nom de f ichier. Il 
faut donc s'assurer que la replication fonctionne bien et effectuer un purge master logs to "<nom-serveur>-bin.xxx" ou xxx est de preference 5 en d essous du fichier en cours (sauf 
en cas de faible espace disque). Si le fichier en cours est le suivant "sql-bin.045" alors effectuer un purge master logs to sql-bin.040".

Slave : Les binlogs peuvent etre supprime de la meme maniere sur le slave que sur le master. Les relay-bin logs sont supprime automatiquement par mysql. 

Resynchronisation d'une réplication Master / Slave

Première méthode

Maintenant que les serveurs MySQL de plate forme Claranet appartiennent tous à la v5, il est possible d'utiliser la commande LOAD DATA sans que le slave se désynchronise quelques heures plus tard.

Pour cela, sur le serveur slave:

- Détruire les bases qui sont répliquées via un DROP DATABASE <BASE>
  (S'assurer que les bases détruites sont bien répliquées en inspectant le champs 
   Replicate_Wild_Do_Table obtenu via la sortie de SHOW SLAVE STATUS \G)
- STOP SLAVE
- Recréer les bases détruites
- LOAD DATA FROM MATER;
- Attendre (2 minutes grand max)
- START SLAVE

Si tout s'est bien passé, nous n'avons pas vu de warnings ou d'erreurs en sortie lors de l'exécution des commandes précédentes.

Maintenant, il est possible que certaines sous-versions appartenant à la 5 sortent un warning lors du LOAD DATA FROM MASTER. Un SHOW WARNINGS montrera que cette commande est obsolète (LOAD DATA) et qu'il est nécessaire d'utiliser la méthode expliquée dans le paragraphe suivant (celle préconisée par MySQL) pour remettre sur pieds la réplication.


Deuxième méthode

Pour faciliter les choses, j'ai créé un script Shell sur le master et sur chaque Slave. Il permet d'effectuer une resynchro globale et complète en quelques minutes, sans trop interrompre le service.

Le script Shell est nommé Mysql-synchro-syncher-slave.sh sur les slaves.

Procédure à suivre :

  • Sur le master executer : Mysql-synchro-syncher-master.sh --lock

Pour info, sur Nord le script effectue alors les actions suivantes :

- FLUSH TABLES WITH READ LOCK
- Copie binaires des tables dans un répertoire temporaire
- RESET MASTER
- UNLOCK TABLES
- Démarrage d'un daemon rsync qui va permettre d'exporter les tables binaires vers les slaves. 
  Ce daemon rsync est lancé en avant-plan : il faudra taper Ctrl+C sur Nord pour le stopper, une fois que
  les slaves auront téléchargé les bases au format binaire.

Pour info, sur les slaves le script effectue alors les actions suivantes :

- Import des bases binaires, dans un répertoire temporaire, depuis le rsync lancé sur Nord
- Arret du serveur MySQL local sur le slave
- Remplacement des bases désynchronisées par les bases binaires importées depuis Nord
- Effacement des infos de synchronisation - équivalent à un RESET SLAVE
- Redémarrage du MySQL local
- Le MySQL se reconnecte au master, et la synchro reprend.

Une fois que tous les slaves sont correctement resynchronisés, arreter le daemon Rsync lancé sur Nord (en tapant Ctrl+C).

  • Procédure manuelle sur un slave
mysql> CHANGE MASTER TO
    -> MASTER_HOST='master.fr.clara.net',
    -> MASTER_PORT=3306,
    -> MASTER_USER='clara_replic',
    -> MASTER_PASSWORD='xxxx',
    -> MASTER_LOG_FILE='xxxxxxx',
    -> MASTER_LOG_POS=xx;
Query OK, 0 rows affected (0.00 sec)

Troisième méthode

1. Sur le slave, exécuter les commandes MySQL suivantes :
STOP SLAVE;
RESET SLAVE;
puis stopper le service et archiver le contenu de /opt/data/mysql (en /opt/data/mysql_archive_#date#.tgz). 
Supprimer le répertoire /opt/data/mysql

2. Sur le master, exécuter les commandes MySQL suivantes :
RESET MASTER;
FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;
/!\ !! conserver le client ouvert pour conserver le lock !!

- Faire un tar over ssh depuis master:/opt/data/mysql vers slave:/opt/data/mysql
 + Exemple : tar cpzvf - /opt/data/mysql | ssh root@slave tar xpzvf - -C /

- Une fois le transfert terminé, exécuter les commandes MySQL suivantes sur le master ::
UNLOCK TABLES;

- Puis sur le slave, relancer le service MySQL et exécuter les commandes MySQL suivantes : 
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=98; (à voir suivant le master status)
START SLAVE;
SHOW SLAVE STATUS;

On doit avoir comme retour :
    Slave_IO_Running: Yes
    Slave_SQL_Running: Yes

Resynchronisation en faisant du slave le master

En cas de defaillance d'un serveur master mysql en master/slave. La bascule du master vers le slave peut se faire de plusieurs facons. Techniquement, le slave est un serveur mysql 
accessible en lecture/ecriture. Il peut theoriquement etre utilise immediatement sans action particuliere. Cependant, il est peut etre interessant de le configurer en master afin 
d'inverser le master et le slave pour eviter une autre coupure de service.

# Etape 1 : Passage du slave en master

En cas de defaillance du master, et dans le cas de la necessite d'inverser le master et le slave, il faut donc deconfigurer le slave pour le reconfigurer en master. La premiere 
chose a faire et de s'assurer que la synchro est bien termine (show slave status) et proceder a l'arret du serveur mysql. Il faut ensuite modifier la configuration du my.cnf :

server-id = 1
log_bin = /var/log/mysql/mysql-bin.log # Le chemin peut changer suivant le serveur

Puis supprimer les binlogs (mysql-bin et relay-bin ou equivalent) et fichiers lies a la synchronisation (master.info et relay-log.info) NE PAS RELANCER LE SERVEUR POUR LE MOMENT. 
Une fois fait, le serveur est un serveur master.

# Etape 2 : Preparer la future remise en place du slave

L'ancien master va etre repare. Ces bases ne seront plus a jour. L'idee est donc de le transformer en slave. Pour cela, il doit avoir le contenu de bases avant toute modification 
qui serait incluses dans les bin logs. Sur l'ancien slave, le nouveau master donc, il faut faire une copie des bases. Pour limiter les I/O disques et accelerer donc la remise en 
oeuvre, un tar.gz du dossier de bases peut etre fait, sinon une copie a plat (cp -rp) fonctionne aussi tres bien. Une fois la copie ou le tar fait, le serveur mysql peut etre lance 
sur le nouveau master. 

# Etape 3 : Basculer le service

Une fois le serveur mysql UP, le service peut lui aussi etre bascule. Il n'y a en effet pas de load balancing, il faut faire des modification cote serveurs effectuant des requetes 
pour que la bascule soit effective. Il existe trois methodes :

    Methode applicative : Modification du ou des fichiers faisant appel au nom du serveur mysql pour mettre le nouveau nom du master. Generalement, la modification est immediate
    Methode DNS : Modification du nom d'hote pour remplacer l'ip du serveur defaillant par le nouveau master. Generalement, il y a un cache DNS, il faut donc relancer le service web 
(ou autres) pour prise en compte. Cela peut etre realise par les DNS ou le fichiers hosts des serveurs client mysql.
    Methode IP : Dans le cas ou cela a ete prevu, il peut y avoir une bascule d'ip (on inverse les ips des 2 serveurs). Cette IP est un alias sur le serveur mysql master. La prise en 
compte est immediate.