Déployer un cluster MySQL Group Replication
Mise-à-jour: 9 janvier 2018
Historiquement, les solutions de haute disponibilité (HA) avec MySQL tournent autour de la fonctionnalité native MySQL Replication: replication asynchrone ou semi-synchrone. Ces modes de replication sont très largement utilisés pour le besoins critiques d’enterprises « at scale » comme Facebook, Twitter, Booking.com, Uber…
Aujourd’hui MySQL propose une nouvelle fonctionnalité native de haute disponibilité :
MySQL Group Replication.
MySQL Group Replication
MySQL Group Replication est un plugin pour MySQL 5.7+ qui fournit nativement de la réplication virtuellement synchrone avec détection/résolution de conflit et cohérence garantie. Ce plugin est disponible sur tous les systèmes d’exploitation supportés par MySQL (Linux, Windows, Solaris, OSX, …)
C’est la fonctionnalité idéale pour les architectures multi-maîtres. Il n’est alors plus nécessaire de gérer le failover de la base de données (à l’aide d’outils comme: mysqlfailover; mysqlrpladmin; MHA).
A noter que le plugin MySQL Group replication est en ce moment en Release Candidate (RC) ce qui veut dire qu’il n’est pas encore conseillé pour la production. C’est néanmoins le bon moment pour le tester (binaires téléchargeable ici). Le statut RC est la dernière étape avant la GA, et selon mon petit doigt ce n’est plus qu’une question de semaines avant la sortie officielle en GA (qui a dit MySQL 5.7.17 ???).
Le plugin MySQL Group Replication est GA et embarqué dans MySQL à partir de la version 5.7.17. Pour télécharger MySQL rendez-vous sur la page : http://www.mysql.com/downloads/
Déployer un cluster de 3 nœuds
La version du plugin lors de l’écriture de cet article est 0.9 disponible avec MySQL 5.7.15 dans le lab de MySQL : http://labs.mysql.com/
Cette article présume que MySQL 5.7.15 est déja installé (installer MySQL).
Article mis-à-jour avec la version 1.0 du plugin, qui est la version GA embarquée dans MySQL 5.7.17.
Cette article présume qu’une version de MySQL égale ou supérieure à 5.7.17 est déja installé (installer MySQL).
Caractéristiques
- Version du serveur : 5.7.17
- Version du plugin : 1.0
- Nœud 1 : 192.168.1.11 : 14115
- Nœud 2 : 192.168.1.9 : 3301
- Nœud 3 : 192.168.1.48 : 5709
Configurer les instances MySQL
Comme toutes technologies, il y a des contraintes et quelques limitations. MySQL Group Replication nécessite :
- MySQL 5.7
- Tables avec le moteur de stockage InnoDB
- Tables avec une clé primaire
- Seul le protocole IPV4 est supporté
- Les DDL en parallèle de DDL/DML exécutés par différents nœuds sur le même objet sont proscrits.
Liste complète : Requirements and Limitations
Au niveau configuration des serveurs il faut:
- Activer le log binaire
- Le log binaire doit être au format ROW :
- Journaliser les mise à jours envoyées par le primaire
- Activer le mode GTID
- master_info_repository et relay_log_info_repository doivent avoir la valeur TABLE
- Désactiver le calcul de la somme de contrôle des événements de réplication
Il faut également avoir une valeur de la variable server_id différente pour chacun des 3 nœuds:
- Nœud 1 : server_id=11
- Nœud 2 : server_id=9
- Nœud 3 : server_id=48
Pour synthétiser, dans le fichiers de configuration (my.cnf / my.ini) du nœud 1, il faut avoir (en plus des infos classiques):
server_id=11 gtid_mode=ON enforce_gtid_consistency=ON master_info_repository=TABLE relay_log_info_repository=TABLE binlog_checksum=NONE log_slave_updates=ON log_bin binlog_format=ROW
Pareil pour les 2 autres, à la valeur de server_id près.
Configuration spécifique à MySQL Group Replication
Le cluster doit avoir un identifiant unique au format UUID:
- le UUID doit être valide
- il doit être définit sur chacune des machines du groupe
La fonction MySQL UUID() permet de générer un… uuid:
node1> SELECT UUID(); +--------------------------------------+ | UUID() | +--------------------------------------+ | 78c1a27c-9dde-11e6-865d-dc53609b8b8d | +--------------------------------------+
- Activer la journalisation des données modifiées par les transactions
- Charger le plugin au démarrage et l’empêcher d’être désinstallé pendant l’exécution
- group_replication = FORCE_PLUS_PERMANENT
- Charger le pluging Group Replication au démarrage du serveur
- plugin_load = group_replication.so
- Donner un nom au cluster au format UUID
- group_replication_group_name = « 78c1a27c-9dde-11e6-865d-dc53609b8b8d »
- Ne pas démarrer automatiquement Group Replication au démarrage de l’instance (au choix)
- Sert à démarrer le cluster. Doit être à OFF (valeur par défaut)
- Permet de choisir la configuration mono-maître (au lieu de multi-maître)
- Adresse (locale) du nœud
- group_replication_local_address = « hostA:port »
- Liste d’adresses des pairs. Utile lorsqu’un nouveau noeud cherche à se mettre à jour
- group_replication_group_seeds = « hostB:port,hostC:port »
Note.
Pour avoir une architecture multi-master ie pouvoir écrire sur toutes les intances à la fois il faut group_replication_single_primary_mode = OFF sur tous les nœuds
Activation du plugin MySQL Group Replication
A partir de la version 5.7.17, MySQL embarque le plugin Group Replication qui se nomme : group_replication.so.
Le plugin n’est évidemment pas activé par défaut, cependant vous avez 2 solutions pour l’activer :
- dans le fichier de configuration comme indiqué précédemment (nécessite un redémarrage de l’instance MySQL)
plugin_load = group_replication.so
- à la volée, avec la commande INSTALL PLUGIN si l’instance est correctement configurée
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
Un fois activé, les informations relatives au plugin sont disponible avec (à faire sur tout les nœuds) :
node[1|2|3]> SELECT PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication'; +-------------------+----------------+---------------+ | PLUGIN_NAME | PLUGIN_VERSION | PLUGIN_STATUS | +-------------------+----------------+---------------+ | group_replication | 1.0 | ACTIVE | +-------------------+----------------+---------------+
Le fichier group_replication.so se trouve dans le répertoire à plugin – plugin_dir:
mysql> SHOW VARIABLES LIKE 'plugin_dir'; +---------------+------------------------------+ | Variable_name | Value | +---------------+------------------------------+ | plugin_dir | /usr/local/mysql/lib/plugin/ | +---------------+------------------------------+
/usr/local/mysql/lib/plugin/ pour ma configuration.
mysql> \! ls -l /usr/local/mysql/lib/plugin/group_replication.so -rwxr-xr-x 1 root mysql 15872361 Nov 28 17:45 /usr/local/mysql/lib/plugin/group_replication.so
Synthétisons encore!
Dans la section [mysqld] du fichier de configuration (my.cnf / my.ini) du nœud 1, il faut ajouter:
## Group Replication specific options plugin_load=group_replication.so group_replication=FORCE_PLUS_PERMANENT transaction_write_set_extraction=XXHASH64 group_replication_group_name="78c1a27c-9dde-11e6-865d-dc53609b8b8d" group_replication_start_on_boot=OFF group_replication_bootstrap_group=OFF group_replication_single_primary_mode=ON group_replication_local_address="192.168.1.11:4406" group_replication_group_seeds="192.168.1.9:4406,192.168.1.48:4406"
Et donc pour les 2 nœuds restant, il faut ajuster:
Nœud 2 :
group_replication_local_address="192.168.1.9:4406" group_replication_group_seeds="192.168.1.11:4406,192.168.1.48:4406"
Nœud 3 :
group_replication_local_address="192.168.1.48:4406" group_replication_group_seeds="192.168.1.11:4406,192.168.1.9:4406"
Note.
Mon environnement étant « exotique » j’ai du configurer les 2 variables qui suivent, pour que le process de restauration fonctionne.
- Nœud 1 : report_port = 14115 / report_host = « 192.168.1.11 »
- Nœud 2 : report_port = 3301 / report_host = « 192.168.1.9 »
- Nœud 3 : report_port = 5709 / report_host = « 192.168.1.48 »
Cependant il est plus que recommandé de configurer correctement nom d’hôte (/etc/hosts; /etc/hostname;) et DNS.
Optionnel : Pour empêcher l’utilisation (malencontreuse) d’autres moteurs de stockage autre qu’InnoDB (non-transactionnel donc), il peut être utile d’ajouter à la conf:
- disabled_storage_engines= »MyISAM,BLACKHOLE,FEDERATED,ARCHIVE »
Le fichier de configuration étant modifié, il faut redémarrer les instances MySQL pour que la nouvelle configuration prenne effet.
A noter quand même que la plupart des variables relatives à Group Replication sont changeable à chaud avec la commande SET GLOBAL <commande>.
Utilisateur de restauration
Cet utilisateur est nécessaire pour le processus de récupération automatique (recovery) lorsqu’un serveur (r)entre dans le groupe.
A créer et à configurer sur tout les nœuds du groupe. Il permettra d’établir une connexion replica/source entre les membres du groupe en cas de process de recovery.
node[1|2|3]> -- Create recovery user SET sql_log_bin=0; CREATE USER gr_user@'%' IDENTIFIED BY 'Mdp5uperS3cr&t'; GRANT REPLICATION SLAVE ON *.* TO gr_user@'%'; FLUSH PRIVILEGES; -- Create recovery channel CHANGE MASTER TO MASTER_USER='gr_user', MASTER_PASSWORD='Mdp5uperS3cr&t' FOR CHANNEL 'group_replication_recovery'; SET sql_log_bin=1;
A partir de MySQL 5.7.19 il est recommandé de configurer les membres du cluster avec la variable super_read_only = 1. Une fois Group Replication démarré, il va ajuster la variable comme il le faut en fonction des états des nœuds (e.g. désactivé pour le(s) primaire(s)).
Plus d’info ici.
Pour une version de MySQL 5.7.19+ donc, dans la section [mysqld] des fichiers de configuration (my.cnf / my.ini) des nœuds 1, 2 et 3 il faut alors ajouter:
super_read_only = 1
On est pas mal là!
Avant d’aller plus loin, une bonne habitude est de vérifier que les serveurs sont correctement configurés.
Vérification de la configuration
Configuration serveur
La commande SHOW GLOBAL VARIABLES permet de voir la valeur des variables serveur.
node1> SHOW GLOBAL VARIABLES WHERE Variable_name IN ('server_id', 'log_bin', 'binlog_format', 'gtid_mode', 'enforce_gtid_consistency', 'log_slave_updates', 'master_info_repository', 'relay_log_info_repository','transaction_write_set_extraction', 'binlog_checksum'); +----------------------------------+----------+ | Variable_name | Value | +----------------------------------+----------+ | binlog_checksum | NONE | | binlog_format | ROW | | enforce_gtid_consistency | ON | | gtid_mode | ON | | log_bin | ON | | log_slave_updates | ON | | master_info_repository | TABLE | | relay_log_info_repository | TABLE | | server_id | 11 | | transaction_write_set_extraction | XXHASH64 | +----------------------------------+----------+
Configuration restauration
node[1|2|3]> SELECT user_name, host, user_password FROM mysql.slave_master_info WHERE channel_name = 'group_replication_recovery'; +-----------+--------+----------------+ | user_name | host | user_password | +-----------+--------+----------------+ | gr_user | <NULL> | Mdp5uperS3cr&t | +-----------+--------+----------------+ SHOW GRANTS FOR gr_user@'%'; +-------------------------------------------------+ | Grants for gr_user@% | +-------------------------------------------------+ | GRANT REPLICATION SLAVE ON *.* TO 'gr_user'@'%' | +-------------------------------------------------+
Configuration Group Replication
node1> SHOW GLOBAL VARIABLES WHERE Variable_name IN ('group_replication_bootstrap_group', 'group_replication_group_name', 'group_replication_group_seeds', 'group_replication_local_address','group_replication_start_on_boot', 'group_replication_single_primary_mode', 'server_uuid', 'super_read_only'); +---------------------------------------+--------------------------------------+ | Variable_name | Value | +---------------------------------------+--------------------------------------+ | group_replication_bootstrap_group | OFF | | group_replication_group_name | 78c1a27c-9dde-11e6-865d-dc53609b8b8d | | group_replication_group_seeds | 192.168.1.9:4406,192.168.1.48:4406 | | group_replication_local_address | 192.168.1.11:4406 | | group_replication_single_primary_mode | ON | | group_replication_start_on_boot | OFF | | server_uuid | dc12fd1a-83ff-11e5-91af-002710b3d914 | | super_read_only | ON | +---------------------------------------+--------------------------------------+
Cela correspond à ce qui a été renseigné un peu plus haut.
Je vous conseille de toujours vérifier les configurations, sur tout les nœuds. Ca permet de gagner du temps et de sauvegarder l’énergie par la suite… « Certified wise DBA »
Déployer le cluster
Le moment tant attendu arrive…
Pour la suite de cet article, je présume que les instances ont les mêmes données, donc le cas présent, pas de données.
Dans le cas contraire il suffit simplement de faire une sauvegarde complète d’une des instances et de la restaurer sur les 2 autres (Backup and Recovery).
Amorcer le cluster
L’amorçage (bootstrap) consiste à créer un groupe d’un seul nœud (faut bien commencer !). Ce dernier va par la suite être en mesure de recevoir d’autres membres. La procédure de bootstrap ne doit donc se faire que sur un seul membre, le tout premier nœud du groupe.
Le nœud 1 est donc désigné volontaire pour l’amorçage.
node1> SET GLOBAL group_replication_bootstrap_group = ON; START GROUP_REPLICATION; SET GLOBAL group_replication_bootstrap_group = OFF;
Revoyons la scène au ralenti…
- j’initie : group_replication_bootstrap_group = ON
- je démarre : START GROUP_REPLICATION
- je termine l’initialisation : group_replication_bootstrap_group = OFF
C’est vraiment important d’exécuter group_replication_bootstrap_group = ON seulement sur le 1er nœud du cluster, sous peine de se retrouver avec des groupes indépendant (split-brain artificiel).
Récupérer des infos sur le cluster c’est facile, avec les tables:
- performance_schema.replication_group_members
- performance_schema.replication_connection_status
node1> SELECT * FROM performance_schema.replication_group_members\G *************************** 1. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: 00014115-1111-1111-1111-111111111111 MEMBER_HOST:192.168.1.11 MEMBER_PORT: 14115 MEMBER_STATE: ONLINE
node1> SELECT * FROM performance_schema.replication_connection_status\G *************************** 1. row *************************** CHANNEL_NAME: group_replication_applier GROUP_NAME: 78c1a27c-9dde-11e6-865d-dc53609b8b8d SOURCE_UUID: 78c1a27c-9dde-11e6-865d-dc53609b8b8d THREAD_ID: NULL SERVICE_STATE: ON COUNT_RECEIVED_HEARTBEATS: 0 LAST_HEARTBEAT_TIMESTAMP: 0000-00-00 00:00:00 RECEIVED_TRANSACTION_SET: 78c1a27c-9dde-11e6-865d-dc53609b8b8d:1 LAST_ERROR_NUMBER: 0 LAST_ERROR_MESSAGE: LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00 *************************** 2. row *************************** CHANNEL_NAME: group_replication_recovery GROUP_NAME: SOURCE_UUID: THREAD_ID: NULL SERVICE_STATE: OFF COUNT_RECEIVED_HEARTBEATS: 0 LAST_HEARTBEAT_TIMESTAMP: 0000-00-00 00:00:00 RECEIVED_TRANSACTION_SET: LAST_ERROR_NUMBER: 0 LAST_ERROR_MESSAGE: LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
Le groupe contient bien un seul membre, 192.168.1.11 aka nœud 1 et il est ONLINE.
Jusqu’ici tout va bien!
Ajouter des nœuds
Un cluster composé d’un seul membre, c’est un bon début. Mais ce n’est évidemment pas suffisant pour avoir de la haute disponibilité avec notre base de données MySQL
Ajout du nœud 2
node2> START GROUP_REPLICATION;
Trop facile !!!
La supervision montre que le cluster est donc maintenant composé de 2 membres, ONLINE!
node2> SELECT * FROM performance_schema.replication_group_members\G *************************** 1. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: 00014115-1111-1111-1111-111111111111 MEMBER_HOST: 192.168.1.11 MEMBER_PORT: 14115 MEMBER_STATE: ONLINE *************************** 2. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: d0853b8c-8d92-11e6-875b-0800273276e6 MEMBER_HOST: 192.168.1.9 MEMBER_PORT: 3301 MEMBER_STATE: ONLINE
node2> SELECT * FROM performance_schema.replication_connection_status\G *************************** 1. row *************************** CHANNEL_NAME: group_replication_applier GROUP_NAME: 78c1a27c-9dde-11e6-865d-dc53609b8b8d SOURCE_UUID: 78c1a27c-9dde-11e6-865d-dc53609b8b8d THREAD_ID: NULL SERVICE_STATE: ON COUNT_RECEIVED_HEARTBEATS: 0 LAST_HEARTBEAT_TIMESTAMP: 0000-00-00 00:00:00 RECEIVED_TRANSACTION_SET: 78c1a27c-9dde-11e6-865d-dc53609b8b8d:1-2:5:7 LAST_ERROR_NUMBER: 0 LAST_ERROR_MESSAGE: LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00 *************************** 2. row *************************** CHANNEL_NAME: group_replication_recovery GROUP_NAME: SOURCE_UUID: THREAD_ID: NULL SERVICE_STATE: OFF COUNT_RECEIVED_HEARTBEATS: 0 LAST_HEARTBEAT_TIMESTAMP: 0000-00-00 00:00:00 RECEIVED_TRANSACTION_SET: LAST_ERROR_NUMBER: 0 LAST_ERROR_MESSAGE: LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
On ne vas pas s’arrêter en si bon chemin
Ajout du nœud 3
Cap ou pas cap ?
node3> START GROUP_REPLICATION;
Le process est évidemment le même.
node3> SELECT * FROM performance_schema.replication_group_members\G *************************** 1. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: 00014115-1111-1111-1111-111111111111 MEMBER_HOST: 192.168.1.11 MEMBER_PORT: 14115 MEMBER_STATE: ONLINE *************************** 2. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: d0853b8c-8d92-11e6-875b-0800273276e6 MEMBER_HOST: 192.168.1.9 MEMBER_PORT: 3301 MEMBER_STATE: ONLINE *************************** 3. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: dc12fd1a-83ff-11e5-91af-002710b3d914 MEMBER_HOST: 192.168.1.48 MEMBER_PORT: 5709 MEMBER_STATE: ONLINE
Les 3 nœuds sont bien actifs et fonctionnels.
node3> SELECT * FROM performance_schema.replication_connection_status\G *************************** 1. row *************************** CHANNEL_NAME: group_replication_applier GROUP_NAME: 78c1a27c-9dde-11e6-865d-dc53609b8b8d SOURCE_UUID: 78c1a27c-9dde-11e6-865d-dc53609b8b8d THREAD_ID: NULL SERVICE_STATE: ON COUNT_RECEIVED_HEARTBEATS: 0 LAST_HEARTBEAT_TIMESTAMP: 0000-00-00 00:00:00 RECEIVED_TRANSACTION_SET: 78c1a27c-9dde-11e6-865d-dc53609b8b8d:4-5:8 LAST_ERROR_NUMBER: 0 LAST_ERROR_MESSAGE: LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00 *************************** 2. row *************************** CHANNEL_NAME: group_replication_recovery GROUP_NAME: SOURCE_UUID: THREAD_ID: NULL SERVICE_STATE: OFF COUNT_RECEIVED_HEARTBEATS: 0 LAST_HEARTBEAT_TIMESTAMP: 0000-00-00 00:00:00 RECEIVED_TRANSACTION_SET: LAST_ERROR_NUMBER: 0 LAST_ERROR_MESSAGE: LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
Alors ? Heureux ?
Il est possible d’avoir jusqu’à 9 membres, donc tu peux y aller Marcel!!!
Identifier le nœud primaire
Rapide récap
Je viens de créer un cluster de 3 nœuds en utilisant le plugin HA natif MySQL Group Replication.
Sur ces 3 nœuds, 2 sont en mode lecture seule (mode: super_read_only) et le troisième en mode lecture/écriture, c’est le nœud primaire.
Un intérêt de cette architecture HA est qu’elle est finalement très proche d’une architecture de réplication classique master/slaves. La grosse différence, et c’est ce qui fait sa puissance, est qu’avec MySQL Group Replication, il n’est plus utile de gérer le failover base de données. Est ça, ce n’est pas rien !
L’information qui permet de savoir quel nœud est primaire est disponible dans la table performance_schema.global_status :
mysql> SELECT * FROM performance_schema.global_status WHERE VARIABLE_NAME='group_replication_primary_member'\G *************************** 1. row *************************** VARIABLE_NAME: group_replication_primary_member VARIABLE_VALUE: 00014115-1111-1111-1111-111111111111
En la joignant avec la table performance_schema.replication_group_members ont obtient un peu plus d’infos:
mysql> SELECT MEMBER_ID, MEMBER_HOST, MEMBER_STATE FROM performance_schema.replication_group_members INNER JOIN performance_schema.global_status ON (MEMBER_ID = VARIABLE_VALUE) WHERE VARIABLE_NAME='group_replication_primary_member'\G *************************** 1. row *************************** MEMBER_ID: 00014115-1111-1111-1111-111111111111 MEMBER_HOST: 192.168.1.11 MEMBER_STATE: ONLINE
Dons cette architecture, le nœud 00014115-1111-1111-1111-111111111111 aka 192.168.1.11 aka nœud 1 est le primaire.
Note.
En mode multi-maître, ils sont tous primaire
Le corollaire immédiat de cette information est que dans cette configuration un seul nœud accepte les écritures. Cependant il est possible de lire sur tous les nœuds.
Sur le nœud 2 -nœud NON primaire
node2> SHOW SCHEMAS; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0,00 sec) CREATE SCHEMA gr_test; ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement SHOW SCHEMAS; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0,00 sec)
Comme prévu les écritures sont impossibles.
Sur le nœud 1 – le nœud primaire
node1> SHOW SCHEMAS; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0,00 sec) CREATE SCHEMA gr_test; Query OK, 1 row affected (0,00 sec) SHOW SCHEMAS; +--------------------+ | Database | +--------------------+ | information_schema | | gr_test | | mysql | | performance_schema | | sys | +--------------------+ 5 rows in set (0,00 sec)
Le schéma (database) gr_test est créé sur le nœud 1. La transaction est répliquée automatiquement sur les autres nœuds.
Arrêt du nœud primaire
Si le nœud primaire n’est plus en ligne (arrêt du serveur pour cause de maintenance ou crash) l’un des 2 autres nœuds devient alors primaire.
node1> SHUTDOWN; -- Arrêt du nœud 1, nœud primaire Query OK, 0 rows affected (0,00 sec)
Les autres membres du cluster sont au courant de la disparition de leur pote.
node3> SELECT MEMBER_ID, MEMBER_HOST, MEMBER_STATE FROM performance_schema.replication_group_members INNER JOIN performance_schema.global_status ON (MEMBER_ID = VARIABLE_VALUE) WHERE VARIABLE_NAME='group_replication_primary_member'\G *************************** 1. row *************************** MEMBER_ID: d0853b8c-8d92-11e6-875b-0800273276e6 MEMBER_HOST: 192.168.1.9 MEMBER_STATE: ONLINE SELECT * FROM performance_schema.replication_group_members\G *************************** 1. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: d0853b8c-8d92-11e6-875b-0800273276e6 MEMBER_HOST: 192.168.1.9 MEMBER_PORT: 3301 MEMBER_STATE: ONLINE *************************** 2. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: dc12fd1a-83ff-11e5-91af-002710b3d914 MEMBER_HOST: 192.168.1.48 MEMBER_PORT: 5709 MEMBER_STATE: ONLINE
Le groupe ne se compose alors plus que de 2 membres : 192.168.1.9 & 192.168.1.48
Et l’un des deux devient primaire.
Le nœud 2 est passé primaire (automatic database failover)
Je peux donc écrire sur le nœud 2 :
node2> CREATE TABLE gr_test.t1(i int auto_increment primary key); Query OK, 0 rows affected (0.12 sec) SHOW TABLES IN gr_test; +-------------------+ | Tables_in_gr_test | +-------------------+ | t1 | +-------------------+
Mais pas sur le nœud 3 (pas une surprise):
node3> SHOW TABLES IN gr_test; +-------------------+ | Tables_in_gr_test | +-------------------+ | t1 | +-------------------+ 1 row in set (0.00 sec) DROP TABLE gr_test.t1; ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement SHOW TABLES IN gr_test; +-------------------+ | Tables_in_gr_test | +-------------------+ | t1 | +-------------------+ 1 row in set (0.00 sec)
Ayant fini la tâche de maintenance sur le nœud 1 je le remet dans le cluster.
Note.
Si la durée d’indisponibilité est longue, il peut être judicieux de restaurer une sauvegarde fraîche sur le serveur avant de le remettre dans le cluster. C’est le même principe qu’avec une architecture de réplication, en utilisant :
Faire revenir un nœud dans le cluster
-- Redémarrer l'instance MySQL -- ... -- Vérifier l'état du nœud 1 node1> SELECT * FROM performance_schema.replication_group_members\G *************************** 1. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: MEMBER_HOST: MEMBER_PORT: NULL MEMBER_STATE: OFFLINE
La variable group_replication_start_on_boot étant à OFF, je dois rajouter le nœud au cluster de manière explicite:
-- Démarrer le nœud 1 node1> START GROUP_REPLICATION; Query OK, 0 rows affected (2,74 sec)
Après s’être enregistré, le « nouveau » membre va se connecter à un autre pour mettre à jour ses données (recovery mode).
Puis finalement participer à nouveau à la vie du cluster:
node1> SELECT * FROM performance_schema.replication_group_members\G *************************** 1. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: 00014115-1111-1111-1111-111111111111 MEMBER_HOST: 192.168.1.11 MEMBER_PORT: 14115 MEMBER_STATE: ONLINE *************************** 2. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: d0853b8c-8d92-11e6-875b-0800273276e6 MEMBER_HOST: 192.168.1.9 MEMBER_PORT: 3301 MEMBER_STATE: ONLINE *************************** 3. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: dc12fd1a-83ff-11e5-91af-002710b3d914 MEMBER_HOST: 192.168.1.48 MEMBER_PORT: 5709 MEMBER_STATE: ONLINE 3 rows in set (0,00 sec) SHOW TABLES IN gr_test; +-------------------+ | Tables_in_gr_test | +-------------------+ | t1 | +-------------------+ 1 row in set (0,00 sec)
A noter que le nœud 1 ne redevient pas primaire (no failback).
node1> DROP TABLE gr_test.t1; ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement SELECT MEMBER_ID, MEMBER_HOST, MEMBER_STATE FROM performance_schema.replication_group_members INNER JOIN performance_schema.global_status ON (MEMBER_ID = VARIABLE_VALUE) WHERE VARIABLE_NAME='group_replication_primary_member'\G *************************** 1. row *************************** MEMBER_ID: d0853b8c-8d92-11e6-875b-0800273276e6 MEMBER_HOST: 192.168.1.9 MEMBER_STATE: ONLINE
Le nœud 2 (d0853b8c-8d92-11e6-875b-0800273276e6 ou 192.168.1.9) est donc bien resté primaire
Note.
Pour avoir une vraie configuration multi-maître il faut modifier la variable group_replication_single_primary_mode sur tout les nœuds du cluster.
Cette manipulation ne peut se faire que cluster arrêté.
Bien bien bien!
Je propose de s’arrêter là même si j’ai encore des choses à raconter. Mais je ne souhaite pas trop rallonger ce long billet.
En guise de conclusion, j’évoquerai simplement les solutions disponibles en frontal, pour que l’application se connecte au cluster.
Router, proxy and Co
- mysqlrouter : Outil développé par MySQL Oracle, il est donc préconisé pour MySQL Group Replication.
La version 2.1 (GA prévue pour cette fin d’année 2017) est intrinsèquement lié à MySQL Group Replication. C’est donc son compagnon naturel. Il faut juste patienter un peu 🙂
La GA actuelle (2.0) peut dépanner mais elle n’est pas suffisamment intégrée (intelligent) avec MySQL Group replication.
A noter que MySQL Group Replication + mysqlrouter 2.1 + MySQL Shell nous donne MySQL InnoDB Cluster.
J’y reviendrai plus en détails dans un prochain article.
OK tu es un impatient, je le sens 🙂
Jette un coup d’œil ici, tu trouveras des liens intéressants
- Proxy SQL : le palliatif idéal en attendant MySQL Router 2.1. Tout le monde en dit du bien. Si tu ne connais pas encore, regardes! tu me remercieras plus tard.
- (maj. 11/01/2017) j’ai écris un tuto : Configurer ProxySQL pour MySQL Group Replication
- HA proxy : certainement le plus connu des 3.
- Si vous êtes familiers avec les connecteurs MySQL, cela peut sans doutes être une solution.
Petite précision pas anodine, tous ces outils sont en GPL.
Aller! Cette fois ci je conclus pour de vrai.
La gestion de la Haute Disponibilité avec MySQL se fait traditionnellement avec :
- MySQL Replication ou MySQL Replication semi-sync
- saupoudré de MySQL Utilities ou de MHA.
- MySQL Cluster
Le plugin MySQL Group Replication apporte une nouvelle solution de HA native et permet également d’avoir une vraie solution multi-maître native et open-source.
Que du bon 🙂
Autres articles Haute Dispo avec MySQL:
- Configurer ProxySQL 1.4 pour MySQL 5.7 Group Replication
- Configurer ProxySQL pour MySQL Group Replication
- FAQ Webinar MySQL Group Replication
- Tester MySQL InnoDB Cluster
- Adopte un… cluster MySQL Group Replication
Thanks for using MySQL!
Architecte Solution Cloud chez Oracle
MySQL Geek, Architecte, DBA, Consultant, Formateur, Auteur, Blogueur et Conférencier.
—–
Blog: www.dasini.net/blog/en/
Twitter: https://twitter.com/freshdaz
SlideShare: www.slideshare.net/freshdaz
Youtube: https://www.youtube.com/channel/UC12TulyJsJZHoCmby3Nm3WQ
—–
[…] un précédent article je vous ai présenté comment déployer un cluster MySQL Group Replication, la nouvelle solution de haute disponibilité de […]
[…] Déployer un cluster MySQL Group Replication […]
[…] MySQL Group Replication est GA et peut donc être utilisé tel quel hors MySQL InnoDB Cluster (voir Déployer un cluster MySQL Group Replication). […]
Bonjour,
Excellent tuto pour la mise en place de GR.
Ayant plusieurs sites interconnectés via une LS (6 ms), nous avons décidé de tester cette solution: 2 serveurs d’un coté et 1 de l’autre.
Le serveur qui est tout seul n’arrive pas à se connecter pour un problème de timeout:
2017-03-13T15:20:39.985648Z 0 [ERROR] Plugin group_replication reported: ‘[GCS] Timeout while waiting for the group communication engine to be ready!’
2017-03-13T15:20:39.985703Z 0 [ERROR] Plugin group_replication reported: ‘[GCS] The group communication engine is not ready for the member to join. Local port: 4901’
2017-03-13T15:20:39.985892Z 0 [Note] Plugin group_replication reported: ‘state 4257 action xa_terminate’
2017-03-13T15:20:39.985919Z 0 [Note] Plugin group_replication reported: ‘new state x_start’
2017-03-13T15:20:39.985924Z 0 [Note] Plugin group_replication reported: ‘state 4257 action xa_exit’
2017-03-13T15:20:39.986045Z 0 [Note] Plugin group_replication reported: ‘Exiting xcom thread’
2017-03-13T15:20:39.986066Z 0 [Note] Plugin group_replication reported: ‘new state x_start’
2017-03-13T15:20:39.986351Z 0 [Warning] Plugin group_replication reported: ‘read failed’
2017-03-13T15:20:40.003693Z 0 [ERROR] Plugin group_replication reported: ‘[GCS] The member was unable to join the group. Local port: 4901’
est ce possible d’augmenter le timeout pour que les serveurs puissent communiquer?
Merci de votre aide.
Xavier.
Bonjour,
Mon problème ne venait pas d’un timeout comme indiqué mais plutot d’un probleme de whitelist…
Probleme résolu.
Xavier
Merci pour ton retour !
Non il n’est pas possible de modifier la valeur du timeout.
Je rajoute sur ma TODO list une mise à jour de l’article pour évoquer la whitelist.
Merci encore.
[…] Déployer un cluster MySQL Group Replication […]
[…] les épisodes précédents on a vu comment déployer « manuellement » MySQL Group Replication, comprendre et tester MySQL InnoDB Cluster ainsi que comment gérer aisément un cluster […]
Merci pour ces explications très claires qui m’ont permis de déployer GROUP REPLICATION sur 3 serveurs très rapidement.
Au moment de la création de l’utilisateur de restauration j’ai dû utiliser
CREATE USER gr_user@’%’ IDENTIFIED BY ‘Mdp5uperS3cr&t’;
GRANT REPLICATION SLAVE ON *.* TO gr_user@’%’;
à la place de:
CREATE USER gr_user@’%’;
GRANT REPLICATION SLAVE ON *.* TO gr_user@’%’ IDENTIFIED BY ‘Mdp5uperS3cr&t’;
pour éviter l’erreur ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
J’ai aussi du passer SELinux en mode permissif pour que le START GROUP_REPLICATION; fonctionne.
Encore merci pour ces explications.
Vincent.
Hello Vincent,
merci pour ton retour.
La syntaxe que j’utilise ie CREATE .. + GRANT… IDENTIFIED est dépréciée depuis quelques versions (c’est le poids de l’habitude) 😀
La syntaxe à utiliser maintenant est bien celle que tu as écrite.
je vais mettre l’article à jour.
[…] A 3 nodes MySQL Group Replication cluster is up and running. […]
Hello,
Très bel article ! merci !
Sous virtualbox avec des VMs Ubuntu 16.04, j’obtiens l’erreur suivante en démarrant le groupe sur le noeud1:
2018-05-19T16:02:05.782897Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: ‘8.0.11’ socket: ‘/var/run/mysqld/mysqld.sock’ port: 3306 MySQL Community Server – GPL.
2018-05-19T16:02:14.741685Z 8 [Warning] [MY-011735] [Repl] Plugin group_replication reported: ‘[GCS] Automatically adding IPv4 localhost address to the whitelist. It is mandatory that it is added.’
2018-05-19T16:02:14.742948Z 10 [System] [MY-010597] [Repl] ‘CHANGE MASTER TO FOR CHANNEL ‘group_replication_applier’ executed’. Previous state master_host= », master_port= 0, master_log_file= », master_log_pos= 4, master_bind= ». New state master_host= », master_port= 0, master_log_file= », master_log_pos= 4, master_bind= ».
2018-05-19T16:02:14.856287Z 0 [ERROR] [MY-011735] [Repl] Plugin group_replication reported: ‘[GCS] Unable to announce tcp port 3306. Port already in use?’
2018-05-19T16:02:14.856332Z 0 [ERROR] [MY-011735] [Repl] Plugin group_replication reported: ‘[GCS] Error joining the group while waiting for the network layer to become ready.’
2018-05-19T16:02:14.856450Z 0 [ERROR] [MY-011735] [Repl] Plugin group_replication reported: ‘[GCS] The member was unable to join the group. Local port: 3306’
2018-05-19T16:03:14.833688Z 8 [ERROR] [MY-011640] [Repl] Plugin group_replication reported: ‘Timeout on wait for view after joining group’
2018-05-19T16:03:14.833757Z 8 [ERROR] [MY-011735] [Repl] Plugin group_replication reported: ‘[GCS] The member is leaving a group without being on one.’
J’ai stoppé Apparmor sur l’ensemble des noeuds par acquis de conscience, mais rien n’y fait, le groupe ne veut pas démarrer.
Merci de ton aide.
Nicolas
Bonjour,
Après un arrêt de ma plate forme, les deux noeuds de mon cluster restent à l’état :
+————–+
| MEMBER_STATE |
+————–+
| RECOVERING |
| ONLINE |
| RECOVERING |
+————–+
Impossible de relancer la synchro, pas d’erreur non plus dans les logs…
Y’a t-il un moyen d’activer un mode verbose ?
server_id = 1
log-bin = /mysql-binlog/replica1-binlog-master
expire_logs_days = 5
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1
gtid_mode = ON
enforce_gtid_consistency = ON
master_info_repository = TABLE
relay_log_info_repository = TABLE
binlog_checksum = NONE
log_slave_updates = ON
binlog_format = ROW
plugin_load=group_replication.so
group_replication=FORCE_PLUS_PERMANENT
transaction_write_set_extraction=XXHASH64
group_replication_group_name= »XXXXX »
group_replication_start_on_boot=OFF
group_replication_bootstrap_group=OFF
group_replication_single_primary_mode=ON
group_replication_local_address= »192.168.XXX.XXX:4406″
group_replication_group_seeds= »192.168.XXX.XXX:4406,192.168.XXX.XXX:4406″
group_replication_ip_whitelist= »192.168.XXX.XXX,192.168.XXX.XXX,192.168.XXX.XXX,127.0.0.1/8″
Hello,
Mon group replication reste bloqué apres un reboot de la plate-forme, impossible de relancer la réplication, pas d’erreur dans les logs.
————–+————-
MEMBER_STATE | MEMBER_ROLE
————–+————-
RECOVERING | SECONDARY
ONLINE | PRIMARY
RECOVERING | SECONDARY
————–+————-
Quelqu’un aurait une idée ?
Bonjour,
Le tuto est super, j’ai pu mettre en place un cluster très rapidement avec mySQL 8.0.11 , mais maintenant je suis bloqué, un noeud à crashé (disk full) et impossible de le remettre dans le group, je passe donc par une réinstall:
dump du master : mysqldump -p –single-transaction –all-databases –triggers –routines –events >dump.sql
restore sur le slave: reset master; source dump.sql; start group_replication;
Tout est bon après quelques ajustements, mais pas de replication vers le nouveau serveur, bien que je n’ai pas de messages d’erreur.
Auras-je louper quelque chose?
Merci
Bonjour,
En fait l’erreur est commune que ce soit sous virtual box, vmware player ou sur une machine physique. Bref je n’arrive toujours pas à faire fonctionner le cluster.
Merci pour toute aide/conseil
Nicolas
[…] noter qu’il est préférable de provisionner ses instances déjà correctement configurées (comme détaillé dans cet article) pour MySQL Group […]
[…] Un cluster MySQL Group Replication de 3 nœuds est configuré et fonctionnel. […]
[…] noter qu’il est préférable de provisionner ses instances déjà correctement configurées (comme détaillé dans cet article) pour MySQL Group […]
[…] 1/ je prépare mes instances « manuellement » (cette tâche peut bien évidemment s’automatiser) comme expliqué dans l’article comment configurer un groupe. […]