Cluster multi master pour MariaDB (et MySQL…) avec Galera
Petite présentation
Galera est une surcouche de MariaDB permettant de mettre en œuvre un cluster au dessus du moteur de stockage InnoDB pour permettre un environnement hautement disponible :
- Réplication multi master
- Réplication synchrone
- Chaque nœud du cluster est utilisable pour un accès lecture/écriture
- La réplication est supportée au travers d’un lien WAN et de la latence que ce type de lien peut comporter
- Contrôle d’admission au cluster intégré
Dans une architecture Galera, les clients SQL vont donc attaquer le cluster via un Load Balancer comme HAProxy qui sera lui-même hautement disponible :
Bien évidemment, cela implique quelques limitations :
- Seul le moteur InnoDB est supporté (MyISAM en alpha)
- La DB mysql qui gère notamment les droits n’est pas comprise dans la réplication
- Toutes les tables doivent avoir une clé primaire, il faudra donc vérifier (ou faire évoluer avec les développeurs le schéma de la base)
- Le verrouillage des tables n’est pas supporté
- Cela ne fonctionne que sous GNU/Linux
Enfin, c’est nettement mieux documenté ici.
Préparation du cluster
Pour exposer le principe de mise en oeuvre, je vais partir sur un cluster à trois noeuds, ce qui correspond au nombre minimal de noeuds nécessaire pour éviter un split brain en cas de panne d’un des deux noeuds. Les trois serveurs db1, db2 et db3 sont tous sous Ubuntu 16.04 pour la démonstration.
On commence donc pas installer les paquets sur les trois serveurs :
sudo apt-get install software-properties-common sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8 sudo add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://mariadb.mirrors.ovh.net/MariaDB/repo/10.2/ubuntu xenial main' sudo apt update sudo apt -y install mariadb-server
Ensuite, il faut que les instances MariaDB écoutent sur le réseau ce qui n’est pas le cas par défaut et pousser les options nécessaires pour que MariaDB soit compatible avec le mode de réplication on va donc ajouter au fichier /etc/mysql/my.cnf :
[mysqld] bind-address=0.0.0.0 binlog_format=ROW innodb_autoinc_lock_mode=2 innodb_flush_log_at_trx_commit=0
Dans ce même fichier, il faut également configurer le cluster. Chaque node doit partager le même nom et la même définition des noeuds du cluster.
Cependant, il faut adapter le nom du node local et son adresse en modifiant chaque wsrep_node_name et wsrep_node_address.
wsrep_cluster_name=MariaDBCluster wsrep_cluster_address="gcomm://192.168.69.71,192.168.69.72,192.168.69.73" wsrep_node_name=db1 wsrep_node_address="192.168.69.71" wsrep_on=ON wsrep_provider=/usr/lib/galera/libgalera_smm.so wsrep_sst_method=rsync
Une fois cette étape passée, il faut initialiser un nouveau cluster via le démarrage du premier noeud, c’est l’étape de boostrap. Cela peut se faire depuis n’importe lequel des nœuds du cluster. Par commodité, ce sera mon noeud db1. La commande suivante va ainsi générer un nouvel UUID de cluster (cela se fait avec le service MariaDB préalablement coupé sur l’ensemble du cluster). La commande est galera_new_cluster et cela revient à exécuter /usr/sbin/mysqld –wsrep-new-cluster.
systemctl stop mysqld.service galera_new_cluster
Toujours sur db1, vérifions que le cluster est opérationnel et comporte un noeud :
root@db1:~# mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster_size';" Enter password: +--------------------+-------+ | Variable_name | Value | +--------------------+-------+ | wsrep_cluster_size | 1 | +--------------------+-------+
Ajout des autres noeuds
Il ne reste plus qu’à démarrer normalement MariaDB sur les autres noeuds db2 et db3 :
systemctl start mysqld.service
Et le cluster doit bien être porté à trois noeuds :
root@db1:~# mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster_size';" Enter password: +--------------------+-------+ | Variable_name | Value | +--------------------+-------+ | wsrep_cluster_size | 3 | +--------------------+-------+
Vérifions un peu plus finement l’état de notre cluster en ne gardant que les valeurs qui nous intéressent :
mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_%';" +------------------------------+----------------------------------------------------------+ | Variable_name | Value | +------------------------------+----------------------------------------------------------+ | wsrep_cluster_size | 3 | | wsrep_cluster_status | Primary | | wsrep_connected | ON | | wsrep_evs_state | OPERATIONAL | | wsrep_incoming_addresses | 192.168.69.72:3306,192.168.69.73:3306,192.168.69.71:3306 | | wsrep_local_state_comment | Synced | | wsrep_provider_version | 25.3.22(r3764) | | wsrep_ready | ON | +------------------------------+----------------------------------------------------------+
A ce propos, la page de monitoring galera est particulièrement bien documentée à ce sujet.
Tests
Sur l’un des serveurs, créons une base avec une table et injectons quelques données :
CREATE DATABASE mydb; USE mydb; CREATE TABLE clients ( id INT PRIMARY KEY AUTO_INCREMENT, nom VARCHAR(60), prenom VARCHAR(60) ); INSERT INTO clients (nom, prenom) VALUES ('Simpson', 'Homer'); INSERT INTO clients (nom, prenom) VALUES ('Marsh', 'Stan'); INSERT INTO clients (nom, prenom) VALUES ('Smith', 'Stan');
Le contenu doit pouvoir être requêté depuis les deux autres serveurs :
root@db2:~# mysql -u root -p mydb -e "select * from clients;" Enter password: +----+---------+--------+ | id | nom | prenom | +----+---------+--------+ | 6 | Simpson | Homer | | 9 | Marsh | Stan | | 12 | Smith | Stan | +----+---------+--------+