wiki/HowtoMySQL/Replication.md

323 lines
12 KiB
Markdown
Raw Permalink Normal View History

2016-11-02 12:12:48 +01:00
---
categories: databases
2017-01-07 16:25:45 +01:00
title: Howto réplication MySQL
2016-11-02 12:18:19 +01:00
...
2016-11-02 12:12:48 +01:00
2017-01-07 16:25:45 +01:00
Pour le guide d'installation et d'usage courant, voir [HowtoMySQL](/HowtoMySQL).
2016-11-02 12:12:48 +01:00
2018-05-10 17:25:46 +02:00
Pour la réplication synchrone avec Galera, voir [HowtoMySQL/Galera](/HowtoMySQL/Galera).
2017-01-07 16:41:16 +01:00
## Préparation d'une réplication MASTER/SLAVE
2016-11-02 12:12:48 +01:00
2017-01-07 16:18:16 +01:00
Il faut :
2016-11-02 12:12:48 +01:00
2017-01-07 16:18:16 +01:00
- soit disposer de deux serveurs MySQL inactifs avec un _datadir_ identique,
- soit réaliser un `mysqldump --master-data` sur le serveur où se trouve les données à conserver :
2016-11-02 12:12:48 +01:00
~~~
# mysqldump --master-data --all-databases --events > mysql.dump
2016-11-02 12:12:48 +01:00
~~~
2023-06-13 11:26:24 +02:00
`--master-data` ajoute un `CHANGE MASTER TO` dans le dump contenant les informations nécessaires à la réplication (nom de fichier et position). Dans certains cas, il peut être nécessaire de faire un `FLUSH PRIVILEGES` après l'injection du dump.
2017-01-07 16:53:55 +01:00
/!\\ **Cette option implique `--lock-all-tables` qui bloque toutes les tables pendant le dump !**
2016-11-02 12:12:48 +01:00
Il faut également :
2017-01-11 22:43:16 +01:00
* autoriser la connexion du serveur MySQL SLAVE vers le serveur MASTER ;
2023-04-19 16:56:19 +02:00
* **activer les [binlogs](/HowtoMySQL#binlogs)** sur le serveur MASTER (on conseille le type _mixed_ en général) ;
2017-01-07 16:25:45 +01:00
* positionner un _server-id_ différent sur chaque serveur (ne pas utiliser 0) ;
2017-01-11 22:43:16 +01:00
* créer un utilisateur dédié pour la réplication sur le serveur MASTER : `GRANT REPLICATION SLAVE ON *.* TO repl@'%' IDENTIFIED BY 'PASSWORD';`.
2016-11-02 12:12:48 +01:00
2017-10-11 09:32:15 +02:00
**Astuce très utile** : pour effectuer des requêtes non prises en compte par la réplication, une astuce est d'utiliser interactivement `SET sql_log_bin` ce qui n'écrira pas les requêtes SQL suivantes dans le binlog du serveur (et elles ne seront donc pas répliquées au serveur SLAVE) :
~~~
mysql> SET sql_log_bin = 0;
~~~
> *Note* : cela nécessite le droit MySQL _SUPER_
## Compatibilité de réplication MariaDB entre des versions différentes :
![tableau compatibilité](/tableau_compatibilité_replication_mariadb.png)
2016-11-02 12:12:48 +01:00
2023-04-13 17:07:42 +02:00
## Activation réplication MASTER/SLAVE avec binlogs (ancien)
2016-11-02 12:12:48 +01:00
2017-01-07 16:53:55 +01:00
Il faut récupérer les informations *MASTER_LOG_FILE* et *MASTER_LOG_POS* :
2017-01-07 16:18:16 +01:00
- soit sur l'un des deux serveurs inactifs avec `SHOW MASTER STATUS` (dans le cas de deux serveurs avec _datadir_ identique),
- soit récupérer l'information dans le `mysqldump --master-data` (avec la commande `head` par exemple).
Sur le serveur SLAVE, exécuter :
2016-11-02 12:12:48 +01:00
~~~
2016-12-16 02:03:44 +01:00
mysql> CHANGE MASTER TO
2017-01-11 22:43:16 +01:00
MASTER_HOST='192.168.0.33',
2016-11-02 12:12:48 +01:00
MASTER_USER='repl',
2017-01-11 22:43:16 +01:00
MASTER_PASSWORD='PASSWORD',
2016-11-02 12:12:48 +01:00
MASTER_LOG_FILE='mysql-bin.NNNNNN',
MASTER_LOG_POS=NNN;
~~~
/!\\ **On recommande d'indiquer les directives *MASTER_LOG_FILE* et *MASTER_LOG_POS* pour éviter des problèmes**
2016-11-02 12:12:48 +01:00
Puis démarrer la réplication sur le serveur B avec la commande : `START SLAVE`.
2023-04-13 18:11:41 +02:00
### Désactivation
2016-11-02 12:12:48 +01:00
Pour supprimer toute trace de réplication (sauf si des infos sont en dur dans la configuration) :
~~~
mysql> RESET SLAVE;
Query OK, 0 rows affected (0.00 sec)
2017-10-11 09:32:15 +02:00
mysql> RESET SLAVE ALL;
Query OK, 0 rows affected (0.00 sec)
2016-11-02 12:12:48 +01:00
~~~
Pour éviter que la réplication démarre automatiquement au démarrage, on ajoutera dans la configuration :
2016-12-16 02:03:44 +01:00
~~~{.ini}
[mysqld]
2016-11-02 12:12:48 +01:00
skip-slave-start
~~~
## (Re)injecter un dump sans écrire dans les binlogs
L'option `--init-command` permet de ne pas écrire dans les binlogs :
~~~
# mysql --init-command="SET SQL_LOG_BIN = 0;" -o mabase < mabase.sql
~~~
ou :
~~~
# zcat mabase.sql.gz | mysql --init-command="SET SQL_LOG_BIN = 0;"
~~~
2016-11-02 12:12:48 +01:00
2023-04-13 17:07:42 +02:00
## Activation réplication MASTER/SLAVE avec GTID
2021-07-27 11:11:41 +02:00
**ATTENTION** : L'implémentation des GTID entre MySQL et MariaDB sont différentes et incompatibles entres-elles.
### Mise en place d'un réplica depuis un dump
Mysqldump avec l'option --master-data ou --dump-slave donne la position GTID en début de fichier de dump, en commentaires.
2021-12-13 11:25:38 +01:00
* `--master-data` : On récupère la position actuelle d'écriture de binlogs (comme show master status).
* `--dump-slave` : On récupère la position actuelle de réplication slave (comme show slave status) pour faire un autre réplica pour le même master
2023-02-22 06:54:49 +01:00
Pour connaitre la valeur GTID avec le fichier binaire et sa position, si on fait un backup physique du master par exemple et qu'on fait un SHOW MASTER STATUS, il faut utiliser la fonction BINLOG_GTID_POS, comme ceci, si le fichier binaire est "master-bin.000001" et sa position "600" par exemple :
~~~
mysql> SELECT BINLOG_GTID_POS("master-bin.000001", 600);
0-1-2
~~~
2023-02-22 06:54:49 +01:00
On peut donc mettre la valeur GTID "0-1-2" sur la variable *gtid_slave_pos*, puis démarrer la réplication avec un CHANGE MASTER TO, en positionnant la variable *master_use_gtid* sur *slave_pos* :
~~~
mysql> SET GLOBAL gtid_slave_pos = "0-1-2";
~~~
~~~
mysql> CHANGE MASTER TO
MASTER_HOST='192.168.0.33',
MASTER_USER='repl',
MASTER_PASSWORD='PASSWORD',
master_use_gtid=slave_pos;
~~~
2023-04-13 17:07:42 +02:00
### Activation réplication MASTER/SLAVE avec Mariabackup
2023-04-13 18:10:56 +02:00
Voir la doc de [Mariabackup](mariabackup#mise-en-place-dune-réplication-esclave-avec-mariabackup)
2023-04-13 18:10:56 +02:00
On peut récupérer la position GTID lors d'un backup fait par Mariabackup dans le fichier `xtrabackup_binlog_info`
2023-04-13 17:03:28 +02:00
### Switcher réplication "ancien mode" vers GTID
Si on a déjà une réplication existante et que l'on veux la basculer en mode GTID, on peut le faire de la façon suivante :
~~~
mysql> STOP SLAVE;
mysql> CHANGE MASTER TO
MASTER_HOST='192.168.0.33',
MASTER_USER='repl',
MASTER_PASSWORD='PASSWORD',
master_use_gtid=current_pos;
mysql> START SLAVE;
~~~
2023-05-03 11:46:43 +02:00
2017-01-11 22:43:16 +01:00
## Configuration avancée
<https://dev.mysql.com/doc/refman/5.6/en/replication-options-slave.html>
### Configuration de la réplication via fichier de configuration
La configuration d'une réplication via la commande `CHANGE MASTER TO […]` est persistente, elle est notamment conservée en cas de redémarrage de MySQL car conservée dans le fichier `master.info` situé par défaut dans le datadir (**y compris le mot de passe en clair !**). Nous conseillons cette méthode, mais on peut également configurer via la configuration de MySQL ainsi :
~~~{.ini}
master-host = 192.0.2.33
master-user = repl
master-password = PASSWORD
#master-port = 3306
#master-connect-retry = 60
#master-info-file = master.info
2017-01-11 23:20:39 +01:00
#slave_compressed_protocol=1
#log-slave-updates
2017-01-11 22:43:16 +01:00
~~~
2017-01-11 23:20:39 +01:00
> *Note* : En cas d'une bande passante réduite, l'option *slave_compressed_protocol* permet une compression des données côté MASTER et décompression des données côté SLAVE (cela consomme évidemment davantage de ressources CPU).
2023-05-03 11:46:43 +02:00
2017-01-11 22:43:16 +01:00
### Configuration d'une réplication partielle
2017-01-11 23:20:39 +01:00
Une manière d'avoir une réplication peut être de ne pas écrire toutes les requêtes dans les [binlogs](/HowtoMySQL#binlogs) sur le serveur MASTER via les options *binlog_do_db*/*binlog_ignore_db* mais ce n'est pas conseillé car les binlogs ont souvent d'autres utilités (vérifier les requêtes, ou servir pour d'autres serveurs SLAVE).
2017-01-11 22:43:16 +01:00
Une manière différente (ou complémentaire) est d'utiliser les directives *replicate-do-db*/*replicate-ignore-db*/*replicate-do-table*/*replicate-ignore-table*/*replicate-wild-do-table*/*replicate-wild-ignore-table* sur le serveur SLAVE.
/!\\ Ces directives ne sont pas parfaites, notamment les requêtes « croisées » du type `USE foo; UPDATE bar.baz SET […]` ne seront pas comprises, ce qui peut poser des problèmes !
Pour ignorer les requêtes concernant la base _mysql_ :
~~~{.ini}
[mysqld]
replicate-ignore-db = mysql
~~~
Pour n'inclure que les requêtes concernant les bases _foo_ et _bar_ :
~~~{.ini}
[mysqld]
replicate-do-db = foo
replicate-do-db = bar
~~~
Pour n'inclure que les requêtes concernant les tables _foo.baz_ et _foo.qux_ :
~~~{.ini}
[mysqld]
replicate-do-db = foo
replicate-do-table = foo.baz
replicate-do-table = foo.qux
~~~
/!\\ **On conseille de toujours utiliser *replicate-do-db* en complément de *replicate-do-table*/*replicate-wild-do-table* sinon les requêtes non spécifiques aux tables ne sont pas filtrées (…par exemple les DROP DATABASE venant du serveur MASTER !!)**
2017-01-12 11:29:19 +01:00
Les directives *replicate-wild-do-table*/*replicate-wild-ignore-table* permettent d'utiliser des expressions régulières avec `%` et `_` (comme pour l'opérateur SQL _LIKE_), exemple :
2017-01-11 22:43:16 +01:00
2017-01-12 11:29:19 +01:00
~~~{.ini}
[mysqld]
replicate-wild-do-table = mysql.%
replicate-wild-ignore-table = foo%.%
~~~
2017-01-11 22:43:16 +01:00
2016-11-02 12:12:48 +01:00
2023-05-03 11:46:43 +02:00
### Activation d'une boucle de réplication MASTER/MASTER
C'est une réplication MASTER/SLAVE des deux côtés.
2016-11-02 12:12:48 +01:00
2023-04-13 11:49:18 +02:00
Utiliser ce type de réplication implique :
2016-11-02 12:12:48 +01:00
2023-05-03 11:46:43 +02:00
* Les INSERT ne sont pas immédiatement écrit car il y a un délai de quelques secondes. En cas, bannir un code qui ferait un INSERT puis un SELECT immédiat de la ligne insérée.
* Ne pas utiliser la directive `NOW()` en SQL.
Étapes :
* Positionner la directive `auto-increment-increment = 10` sur chaque serveur
* Positionner la directive `auto-increment-offset` avec une valeur numérique différente sur chaque serveur (par exemple 0, 1, 2 etc.)
* Mettre en place une réplication MASTER/SLAVE classique, soit avec un mysqldump --master-data, soit avec Mariabackup comme indiqué plus haut.
* Une fois le MASTER/SLAVE synchronisé, sur le MASTER où l'on veut configurer un SLAVE, vérifier que la variable `gtid_slave_pos` est bien vide :
~~~
2023-06-13 11:26:24 +02:00
mysql> show variables like 'gtid_slave_pos';
2023-05-03 11:46:43 +02:00
Empty set
~~~
* Puis, mettre en place la partie SLAVE avec un `CHANGE MASTER TO` depuis le MASTER vers le SLAVE :
2016-11-02 12:12:48 +01:00
2023-05-03 11:46:43 +02:00
~~~
mysql> CHANGE MASTER TO
MASTER_HOST='192.168.0.33',
MASTER_USER='repl',
MASTER_PASSWORD='PASSWORD',
master_use_gtid=slave_pos;
~~~
2017-01-11 23:20:39 +01:00
### Réplications en chaîne
La règle de base de la réplication MySQL est : **un serveur SLAVE ne peut avoir qu'un seul MASTER**.
Cela n'empêche pas d'avoir plusieurs serveurs SLAVE pour un serveur MASTER. Et les serveurs SLAVE peuvent également être MASTER de plusieurs serveurs SLAVES... ce qui permet de faire des chaînes complexes de réplications.
Exemple avec 3 serveurs MASTER/MASTER/MASTER :
~~~
Serveur A -> Serveur B -> Serveur C [-> Serveur A]
~~~
Exemple avec de nombreux serveurs :
~~~
Serveur A <-> Serveur B
\ \
\--> Serveur C \--> Serveur F
\--> Serveur D \--> Serveur G
\--> Serveur E \---> Serveur H
\
\--> Serveur I
2017-01-11 23:20:39 +01:00
\--> Serveur J
~~~
2017-02-10 10:57:03 +01:00
Dans ces cas, il est important d'activer l'option *log-slave-updates* permettant de générer des binlogs à partir des données reçues via la réplication et permettre ainsi d'être MASTER et transmettre ces données à un autre serveur SLAVE :
2017-01-11 23:20:39 +01:00
~~~{.ini}
[mysqld]
log-slave-updates
~~~
2016-11-02 12:12:48 +01:00
2017-02-10 14:16:45 +01:00
> **Note** : On pourrait penser que `log-slave-updates` provoque une boucle dans une situation master-master. Mais MySQL est « intelligent », il va ignorer les requêtes de réplications qui contiennent son server-id. A → B (avec server-id de A) → A (ignoré).
2017-01-07 16:25:45 +01:00
2017-12-21 11:11:07 +01:00
## Monitoring
2023-04-13 17:23:07 +02:00
2018-06-05 17:36:11 +02:00
### Icinga/nagios
2017-12-21 11:11:07 +01:00
Pour surveiller que la réplication se fait bien et n'est pas en retard ou cassé par une erreur, on peut mettre en place un check nrpe *mysql_slave*
Il faut pour cela donner les droits "REPLICATION CLIENT" a l'utilisateur MySQL nrpe :
~~~
GRANT REPLICATION CLIENT on *.* TO 'nrpe'@'localhost' IDENTIFIED BY 'PASSWORD';
~~~
2019-01-16 10:15:59 +01:00
### pt-heartbeat
2024-03-08 16:16:59 +01:00
Déplacé sur la page de [Percona Toolkit](/HowtoPerconaToolkit#pt-heartbeat).
2019-01-16 10:15:59 +01:00
2023-04-13 17:41:09 +02:00
## Contrôle intégrité d'une réplication
2016-11-02 12:12:48 +01:00
2024-03-08 16:16:59 +01:00
Déplacé sur la page de [Percona Toolkit](/HowtoPerconaToolkit#pt-table-checksum).
2020-08-05 09:03:52 +02:00
## Actions sur les slaves en mode réplication par Channel
Faire un `SHOW SLAVE STATUS\G` pour connaitre le `Channel_Name`, puis faire les actions classiques, `START`, `STOP`, `RESET`.
Exemple :
~~~
2023-09-29 11:21:36 +02:00
mysql> STOP SLAVE FOR CHANNEL "Channel_Name";
2020-08-05 09:03:52 +02:00
Query OK, 0 rows affected (2.01 sec)
2023-09-29 11:21:36 +02:00
mysql> RESET SLAVE ALL FOR CHANNEL "Channel_Name";
2020-08-05 09:03:52 +02:00
Query OK, 0 rows affected (0.02 sec)
2022-10-25 15:36:52 +02:00
~~~
## Erreurs de réplication
2023-06-13 11:26:24 +02:00
Déplacé sur la page des [erreurs](Replication/Troubleshooting)