Déployer un cluster MySQL Group Replication

novembre 8, 2016

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:

 

 

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 |
+--------------------------------------+

 

 

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:

 

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

 

  • 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 :

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:

 

 

Thanks for using MySQL!

20 Responses to “Déployer un cluster MySQL Group Replication”

  1. […] 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 […]

  2. […] Déployer un cluster MySQL Group Replication […]

  3. […] MySQL Group Replication est GA et peut donc être utilisé tel quel hors MySQL InnoDB Cluster (voir Déployer un cluster MySQL Group Replication). […]

  4. 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.

  5. Bonjour,

    Mon problème ne venait pas d’un timeout comme indiqué mais plutot d’un probleme de whitelist…

    Probleme résolu.

    Xavier

  6. 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.

  7. […] Déployer un cluster MySQL Group Replication […]

  8. […] 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 […]

  9. 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.

  10. 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.

  11. […] A 3 nodes MySQL Group Replication cluster is up and running. […]

  12. 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

  13. 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″

  14. 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 ?

  15. 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

  16. 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

  17. […] 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 […]

  18. […] Un cluster MySQL Group Replication de 3 nœuds est configuré et fonctionnel. […]

  19. […] 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 […]

  20. […] 1/ je prépare mes instances « manuellement » (cette tâche peut bien évidemment s’automatiser) comme expliqué dans l’article comment configurer un groupe. […]